[dataset] simplify saving/reading of TLVs in/from secure storage (#9626)

This commit simplifies the handling of Dataset TLVs that need to be
securely stored when the `PLATFORM_KEY_REFERENCES_ENABLE` feature is
enabled. Two new methods are added to the `Dataset` class:

- `SaveTlvInSecureStorageAndClearValue()` which  saves the value of a
  given TLV type in secure storage and clears the TLV value by
  setting all value bytes to zero.

- `ReadTlvFromSecureStorage()` which reads the TLV value back from
  secure storage and updates it in the `Dataset`.

These methods are used by `DatasetLocal` to manage the set of TLVs
that need to be securely stored defined by a constant array of
`SecurelyStoredTlv` entries. Each entry provides the TLV type
along with the associated `Crypto::Storage::KeyRef` to use for
active or pending Dataset.
This commit is contained in:
Abtin Keshavarzian
2023-11-28 09:24:27 -08:00
committed by GitHub
parent dc616d6a6c
commit c805678511
4 changed files with 116 additions and 80 deletions
+40
View File
@@ -605,5 +605,45 @@ void Dataset::ConvertToActive(void)
const char *Dataset::TypeToString(Type aType) { return (aType == kActive) ? "Active" : "Pending"; }
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
void Dataset::SaveTlvInSecureStorageAndClearValue(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef)
{
using namespace ot::Crypto::Storage;
Tlv *tlv = GetTlv(aTlvType);
VerifyOrExit(tlv != nullptr);
VerifyOrExit(tlv->GetLength() > 0);
SuccessOrAssert(ImportKey(aKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent, tlv->GetValue(),
tlv->GetLength()));
memset(tlv->GetValue(), 0, tlv->GetLength());
exit:
return;
}
Error Dataset::ReadTlvFromSecureStorage(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef)
{
using namespace ot::Crypto::Storage;
Error error = kErrorNone;
Tlv *tlv = GetTlv(aTlvType);
size_t readLength;
VerifyOrExit(tlv != nullptr);
VerifyOrExit(tlv->GetLength() > 0);
SuccessOrExit(error = ExportKey(aKeyRef, tlv->GetValue(), tlv->GetLength(), readLength));
VerifyOrExit(readLength == tlv->GetLength(), error = OT_ERROR_FAILED);
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
} // namespace MeshCoP
} // namespace ot
+29
View File
@@ -918,6 +918,35 @@ public:
*/
static const char *TypeToString(Type aType);
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
/**
* Saves a given TLV value in secure storage and clears the TLV value by setting all value bytes to zero.
*
* If the Dataset does not contain the @p aTlvType, no action is performed.
*
* @param[in] aTlvType The TLV type.
* @param[in] aKeyRef The `KeyRef` to use with secure storage.
*
*/
void SaveTlvInSecureStorageAndClearValue(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef);
/**
* Reads and updates a given TLV value in Dataset from secure storage.
*
* If the Dataset does not contain the @p aTlvType, no action is performed and `kErrorNone` is returned.
*
* @param[in] aTlvType The TLV type.
* @param[in] aKeyRef The `KeyRef` to use with secure storage.
*
* @retval kErrorNone Successfully read the TLV value from secure storage and updated the Dataset.
* @retval KErrorFailed Could not read the @aKeyRef from secure storage.
*
*/
Error ReadTlvFromSecureStorage(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef);
#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
private:
void RemoveTlv(Tlv *aTlv);
+30 -78
View File
@@ -218,112 +218,64 @@ exit:
}
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
const DatasetLocal::SecurelyStoredTlv DatasetLocal::kSecurelyStoredTlvs[] = {
{
Tlv::kNetworkKey,
Crypto::Storage::kActiveDatasetNetworkKeyRef,
Crypto::Storage::kPendingDatasetNetworkKeyRef,
},
{
Tlv::kPskc,
Crypto::Storage::kActiveDatasetPskcRef,
Crypto::Storage::kPendingDatasetPskcRef,
},
};
void DatasetLocal::DestroySecurelyStoredKeys(void) const
{
using namespace Crypto::Storage;
KeyRef networkKeyRef = IsActive() ? kActiveDatasetNetworkKeyRef : kPendingDatasetNetworkKeyRef;
KeyRef pskcRef = IsActive() ? kActiveDatasetPskcRef : kPendingDatasetPskcRef;
// Destroy securely stored keys associated with the given operational dataset type.
DestroyKey(networkKeyRef);
DestroyKey(pskcRef);
for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
{
Crypto::Storage::DestroyKey(entry.GetKeyRef(mType));
}
}
void DatasetLocal::MoveKeysToSecureStorage(Dataset &aDataset) const
{
using namespace Crypto::Storage;
KeyRef networkKeyRef = IsActive() ? kActiveDatasetNetworkKeyRef : kPendingDatasetNetworkKeyRef;
KeyRef pskcRef = IsActive() ? kActiveDatasetPskcRef : kPendingDatasetPskcRef;
NetworkKeyTlv *networkKeyTlv = aDataset.GetTlv<NetworkKeyTlv>();
PskcTlv *pskcTlv = aDataset.GetTlv<PskcTlv>();
if (networkKeyTlv != nullptr)
for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
{
// If the dataset contains a network key, put it in the secure storage
// and zero the corresponding TLV element.
NetworkKey networkKey;
SuccessOrAssert(ImportKey(networkKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent,
networkKeyTlv->GetNetworkKey().m8, NetworkKey::kSize));
networkKey.Clear();
networkKeyTlv->SetNetworkKey(networkKey);
}
if (pskcTlv != nullptr)
{
// If the dataset contains a PSKC, put it in the secure storage and zero
// the corresponding TLV element.
Pskc pskc;
SuccessOrAssert(ImportKey(pskcRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent,
pskcTlv->GetPskc().m8, Pskc::kSize));
pskc.Clear();
pskcTlv->SetPskc(pskc);
aDataset.SaveTlvInSecureStorageAndClearValue(entry.mTlvType, entry.GetKeyRef(mType));
}
}
void DatasetLocal::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
{
using namespace Crypto::Storage;
bool moveKeys = false;
KeyRef networkKeyRef = IsActive() ? kActiveDatasetNetworkKeyRef : kPendingDatasetNetworkKeyRef;
KeyRef pskcRef = IsActive() ? kActiveDatasetPskcRef : kPendingDatasetPskcRef;
NetworkKeyTlv *networkKeyTlv = aDataset.GetTlv<NetworkKeyTlv>();
PskcTlv *pskcTlv = aDataset.GetTlv<PskcTlv>();
bool moveKeys = false;
size_t keyLen;
Error error;
// If reading any of the TLVs fails, it indicates they are not yet
// stored in secure storage and are still contained in the `Dataset`
// read from `Settings`. In this case, we move the keys to secure
// storage and then clear them from 'Settings'.
if (networkKeyTlv != nullptr)
for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
{
// If the dataset contains a network key, its real value must have been moved to
// the secure storage upon saving the dataset, so restore it back now.
NetworkKey networkKey;
error = ExportKey(networkKeyRef, networkKey.m8, NetworkKey::kSize, keyLen);
if (error != kErrorNone)
if (aDataset.ReadTlvFromSecureStorage(entry.mTlvType, entry.GetKeyRef(mType)) != kErrorNone)
{
// If ExportKey fails, key is not in secure storage and is stored in settings
moveKeys = true;
}
else
{
OT_ASSERT(keyLen == NetworkKey::kSize);
networkKeyTlv->SetNetworkKey(networkKey);
}
}
if (pskcTlv != nullptr)
{
// If the dataset contains a PSKC, its real value must have been moved to
// the secure storage upon saving the dataset, so restore it back now.
Pskc pskc;
error = ExportKey(pskcRef, pskc.m8, Pskc::kSize, keyLen);
if (error != kErrorNone)
{
// If ExportKey fails, key is not in secure storage and is stored in settings
moveKeys = true;
}
else
{
OT_ASSERT(keyLen == Pskc::kSize);
pskcTlv->SetPskc(pskc);
}
}
if (moveKeys)
{
// Clear the networkkey and Pskc stored in the settings and move them to secure storage.
// Store the network key and PSKC in the secure storage instead of settings.
Dataset dataset;
dataset.Set(GetType(), aDataset);
MoveKeysToSecureStorage(dataset);
SuccessOrAssert(error = Get<Settings>().SaveOperationalDataset(mType, dataset));
SuccessOrAssert(Get<Settings>().SaveOperationalDataset(mType, dataset));
}
}
#endif
#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
} // namespace MeshCoP
} // namespace ot
+17 -2
View File
@@ -184,14 +184,29 @@ public:
Error Save(const Dataset &aDataset);
private:
bool IsActive(void) const { return (mType == Dataset::kActive); }
void SetTimestamp(const Dataset &aDataset);
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
struct SecurelyStoredTlv
{
Crypto::Storage::KeyRef GetKeyRef(Dataset::Type aType) const
{
return (aType == Dataset::kActive) ? mActiveKeyRef : mPendingKeyRef;
}
Tlv::Type mTlvType;
Crypto::Storage::KeyRef mActiveKeyRef;
Crypto::Storage::KeyRef mPendingKeyRef;
};
static const SecurelyStoredTlv kSecurelyStoredTlvs[];
void MoveKeysToSecureStorage(Dataset &aDataset) const;
void DestroySecurelyStoredKeys(void) const;
void EmplaceSecurelyStoredKeys(Dataset &aDataset) const;
#endif
bool IsActive(void) const { return (mType == Dataset::kActive); }
void SetTimestamp(const Dataset &aDataset);
Timestamp mTimestamp; ///< Active or Pending Timestamp
TimeMilli mUpdateTime; ///< Local time last updated
Dataset::Type mType; ///< Active or Pending