blob: a3a4a480430979b96bc7b687ee795fe3429f6e46 [file] [log] [blame]
/*
* 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 <crypto/CHIPCryptoPAL.h>
#include <crypto/OperationalKeystore.h>
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/core/DataModelTypes.h>
#include <lib/core/TLV.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/SafeInt.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/support/SafePointerCast.h>
#include "K32W1PersistentStorageOpKeystore.h"
#include "sss_crypto.h"
namespace chip {
using namespace chip::Crypto;
static inline sss_sscp_object_t * to_keypair(P256KeypairContext * context)
{
return SafePointerCast<sss_sscp_object_t *>(context);
}
CHIP_ERROR P256KeypairSSS::ExportBlob(P256SerializedKeypairSSS & output) const
{
VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED);
sss_sscp_object_t * keypair = to_keypair(&mKeypair);
size_t keyBlobLen = output.Capacity();
auto res = sss_sscp_key_store_export_key(&g_keyStore, keypair, output.Bytes(), &keyBlobLen, kSSS_blobType_ELKE_blob);
VerifyOrReturnError(res == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
output.SetLength(keyBlobLen);
return CHIP_NO_ERROR;
}
CHIP_ERROR P256KeypairSSS::ImportBlob(P256SerializedKeypairSSS & input)
{
sss_sscp_object_t * keypair = to_keypair(&mKeypair);
if (false == mInitialized)
{
auto res = sss_sscp_key_object_init(keypair, &g_keyStore);
VerifyOrReturnError(res == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
/* Allocate key handle */
res = sss_sscp_key_object_allocate_handle(keypair, 0x0u, kSSS_KeyPart_Pair, kSSS_CipherType_EC_NIST_P,
3 * kP256_PrivateKey_Length, SSS_KEYPROP_OPERATION_ASYM);
VerifyOrReturnError(res == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
}
VerifyOrExit((sss_sscp_key_store_import_key(&g_keyStore, keypair, input.Bytes(), input.Length(), kP256_PrivateKey_Length * 8,
kSSS_blobType_ELKE_blob) == kStatus_SSS_Success),
CHIP_ERROR_INTERNAL);
mInitialized = true;
exit:
return CHIP_NO_ERROR;
}
bool K32W1PersistentStorageOpKeystore::HasOpKeypairForFabric(FabricIndex fabricIndex) const
{
VerifyOrReturnError(mStorage != nullptr, false);
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false);
// If there was a pending keypair, then there's really a usable key
if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex) && (mPendingKeypair != nullptr))
{
return true;
}
P256SerializedKeypairSSS buf;
uint16_t keySize = static_cast<uint16_t>(buf.Capacity());
CHIP_ERROR err =
mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), buf.Bytes(), keySize);
return (err == CHIP_NO_ERROR && (keySize == SSS_KEY_PAIR_BLOB_SIZE));
}
CHIP_ERROR K32W1PersistentStorageOpKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex,
MutableByteSpan & outCertificateSigningRequest)
{
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
// If a key is pending, we cannot generate for a different fabric index until we commit or revert.
if ((mPendingFabricIndex != kUndefinedFabricIndex) && (fabricIndex != mPendingFabricIndex))
{
return CHIP_ERROR_INVALID_FABRIC_INDEX;
}
VerifyOrReturnError(outCertificateSigningRequest.size() >= Crypto::kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL);
// Replace previous pending keypair, if any was previously allocated
ResetPendingKey();
mPendingKeypair = Platform::New<P256KeypairSSS>();
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY);
mPendingKeypair->Initialize(Crypto::ECPKeyTarget::ECDSA);
size_t csrLength = outCertificateSigningRequest.size();
CHIP_ERROR err = mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength);
if (err != CHIP_NO_ERROR)
{
ResetPendingKey();
return err;
}
outCertificateSigningRequest.reduce_size(csrLength);
mPendingFabricIndex = fabricIndex;
return CHIP_NO_ERROR;
}
CHIP_ERROR K32W1PersistentStorageOpKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex,
const Crypto::P256PublicKey & nocPublicKey)
{
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
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 K32W1PersistentStorageOpKeystore::CommitOpKeypairForFabric(FabricIndex fabricIndex)
{
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
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);
P256SerializedKeypairSSS tmpKeyBlob;
uint16_t keyBlobLen = tmpKeyBlob.Capacity();
mPendingKeypair->ExportBlob(tmpKeyBlob);
ReturnErrorOnFailure(
mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), tmpKeyBlob.Bytes(), keyBlobLen));
// If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key.
ResetPendingKey();
return CHIP_NO_ERROR;
}
CHIP_ERROR K32W1PersistentStorageOpKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex)
{
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
// Remove pending state if matching
if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex))
{
RevertPendingKeypair();
}
CHIP_ERROR err = mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName());
if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
{
err = CHIP_ERROR_INVALID_FABRIC_INDEX;
}
return err;
}
void K32W1PersistentStorageOpKeystore::RevertPendingKeypair()
{
VerifyOrReturn(mStorage != nullptr);
// Just reset the pending key, we never stored anything
ResetPendingKey();
}
CHIP_ERROR K32W1PersistentStorageOpKeystore::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
Crypto::P256ECDSASignature & outSignature) const
{
CHIP_ERROR error = CHIP_NO_ERROR;
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex))
{
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL);
// We have an override key: sign with it!
return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature);
}
P256SerializedKeypairSSS keyBlob;
uint16_t keyBlobLen = keyBlob.Capacity();
keyBlob.SetLength(keyBlobLen);
if (fabricIndex != mCachedFabricIndex)
{
error =
mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), keyBlob.Bytes(), keyBlobLen);
keyBlob.SetLength(keyBlobLen);
if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
{
error = CHIP_ERROR_INVALID_FABRIC_INDEX;
}
ReturnErrorOnFailure(error);
if (nullptr == mCachedKeypair)
{
mCachedKeypair = Platform::New<P256KeypairSSS>();
VerifyOrReturnError(mCachedKeypair != nullptr, CHIP_ERROR_NO_MEMORY);
}
VerifyOrReturnError(mCachedKeypair->ImportBlob(keyBlob) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL);
}
return mCachedKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature);
}
Crypto::P256Keypair * K32W1PersistentStorageOpKeystore::AllocateEphemeralKeypairForCASE()
{
// DO NOT CUT AND PASTE without considering the ReleaseEphemeralKeypair().
// If allocating a derived class, then `ReleaseEphemeralKeypair` MUST
// de-allocate the derived class after up-casting the base class pointer.
return Platform::New<Crypto::P256Keypair>();
}
void K32W1PersistentStorageOpKeystore::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair)
{
// DO NOT CUT AND PASTE without considering the AllocateEphemeralKeypairForCASE().
// This must delete the same concrete class as allocated in `AllocateEphemeralKeypairForCASE`
Platform::Delete<Crypto::P256Keypair>(keypair);
}
} // namespace chip