@@ -86,6 +86,54 @@ CHIP_ERROR StoreOperationalKey(FabricIndex fabricIndex, PersistentStorageDelegat
86
86
return CHIP_NO_ERROR;
87
87
}
88
88
89
+ CHIP_ERROR ExportStoredOpKey (FabricIndex fabricIndex, PersistentStorageDelegate * storage,
90
+ Crypto::P256SerializedKeypair & serializedOpKey)
91
+ {
92
+ VerifyOrReturnError (storage != nullptr , CHIP_ERROR_INVALID_ARGUMENT);
93
+ VerifyOrReturnError (IsValidFabricIndex (fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
94
+
95
+ // Use a SensitiveDataBuffer to get RAII secret data clearing on scope exit.
96
+ Crypto::SensitiveDataBuffer<OpKeyTLVMaxSize ()> buf;
97
+
98
+ // Load up the operational key structure from storage
99
+ uint16_t size = static_cast <uint16_t >(buf.Capacity ());
100
+ ReturnErrorOnFailure (
101
+ storage->SyncGetKeyValue (DefaultStorageKeyAllocator::FabricOpKey (fabricIndex).KeyName (), buf.Bytes (), size));
102
+
103
+ buf.SetLength (static_cast <size_t >(size));
104
+
105
+ // Read-out the operational key TLV entry.
106
+ TLV::ContiguousBufferTLVReader reader;
107
+ reader.Init (buf.Bytes (), buf.Length ());
108
+
109
+ ReturnErrorOnFailure (reader.Next (TLV::kTLVType_Structure , TLV::AnonymousTag ()));
110
+ TLV::TLVType containerType;
111
+ ReturnErrorOnFailure (reader.EnterContainer (containerType));
112
+
113
+ ReturnErrorOnFailure (reader.Next (kOpKeyVersionTag ));
114
+ uint16_t opKeyVersion;
115
+ ReturnErrorOnFailure (reader.Get (opKeyVersion));
116
+ VerifyOrReturnError (opKeyVersion == kOpKeyVersion , CHIP_ERROR_VERSION_MISMATCH);
117
+
118
+ ReturnErrorOnFailure (reader.Next (kOpKeyDataTag ));
119
+ {
120
+ ByteSpan keyData;
121
+ ReturnErrorOnFailure (reader.GetByteView (keyData));
122
+
123
+ // Unfortunately, we have to copy the data into a P256SerializedKeypair.
124
+ VerifyOrReturnError (keyData.size () <= serializedOpKey.Capacity (), CHIP_ERROR_BUFFER_TOO_SMALL);
125
+
126
+ // Before doing anything with the key, validate format further.
127
+ ReturnErrorOnFailure (reader.ExitContainer (containerType));
128
+ ReturnErrorOnFailure (reader.VerifyEndOfContainer ());
129
+
130
+ memcpy (serializedOpKey.Bytes (), keyData.data (), keyData.size ());
131
+ serializedOpKey.SetLength (keyData.size ());
132
+ }
133
+
134
+ return CHIP_NO_ERROR;
135
+ }
136
+
89
137
/* * WARNING: This can leave the operational key on the stack somewhere, since many of the platform
90
138
* APIs use stack buffers and do not sanitize! This implementation is for example purposes
91
139
* only of the API and it is recommended to avoid directly accessing raw private key bits
@@ -106,56 +154,17 @@ CHIP_ERROR SignWithStoredOpKey(FabricIndex fabricIndex, PersistentStorageDelegat
106
154
}
107
155
108
156
// Scope 1: Load up the keypair data from storage
157
+ P256SerializedKeypair serializedOpKey;
158
+ CHIP_ERROR err = ExportStoredOpKey (fabricIndex, storage, serializedOpKey);
159
+ if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err)
109
160
{
110
- // Use a SensitiveDataBuffer to get RAII secret data clearing on scope exit.
111
- Crypto::SensitiveDataBuffer<OpKeyTLVMaxSize ()> buf;
112
-
113
- // Load up the operational key structure from storage
114
- uint16_t size = static_cast <uint16_t >(buf.Capacity ());
115
- CHIP_ERROR err =
116
- storage->SyncGetKeyValue (DefaultStorageKeyAllocator::FabricOpKey (fabricIndex).KeyName (), buf.Bytes (), size);
117
- if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
118
- {
119
- err = CHIP_ERROR_INVALID_FABRIC_INDEX;
120
- }
121
- ReturnErrorOnFailure (err);
122
- buf.SetLength (static_cast <size_t >(size));
123
-
124
- // Read-out the operational key TLV entry.
125
- TLV::ContiguousBufferTLVReader reader;
126
- reader.Init (buf.Bytes (), buf.Length ());
127
-
128
- ReturnErrorOnFailure (reader.Next (TLV::kTLVType_Structure , TLV::AnonymousTag ()));
129
- TLV::TLVType containerType;
130
- ReturnErrorOnFailure (reader.EnterContainer (containerType));
131
-
132
- ReturnErrorOnFailure (reader.Next (kOpKeyVersionTag ));
133
- uint16_t opKeyVersion;
134
- ReturnErrorOnFailure (reader.Get (opKeyVersion));
135
- VerifyOrReturnError (opKeyVersion == kOpKeyVersion , CHIP_ERROR_VERSION_MISMATCH);
136
-
137
- ReturnErrorOnFailure (reader.Next (kOpKeyDataTag ));
138
- {
139
- ByteSpan keyData;
140
- Crypto::P256SerializedKeypair serializedOpKey;
141
- ReturnErrorOnFailure (reader.GetByteView (keyData));
142
-
143
- // Unfortunately, we have to copy the data into a P256SerializedKeypair.
144
- VerifyOrReturnError (keyData.size () <= serializedOpKey.Capacity (), CHIP_ERROR_BUFFER_TOO_SMALL);
145
-
146
- // Before doing anything with the key, validate format further.
147
- ReturnErrorOnFailure (reader.ExitContainer (containerType));
148
- ReturnErrorOnFailure (reader.VerifyEndOfContainer ());
149
-
150
- memcpy (serializedOpKey.Bytes (), keyData.data (), keyData.size ());
151
- serializedOpKey.SetLength (keyData.size ());
152
-
153
- // Load-up key material
154
- // WARNING: This makes use of the raw key bits
155
- ReturnErrorOnFailure (transientOperationalKeypair->Deserialize (serializedOpKey));
156
- }
161
+ return CHIP_ERROR_INVALID_FABRIC_INDEX;
157
162
}
158
163
164
+ // Load-up key material
165
+ // WARNING: This makes use of the raw key bits
166
+ ReturnErrorOnFailure (transientOperationalKeypair->Deserialize (serializedOpKey));
167
+
159
168
// Scope 2: Sign message with the keypair
160
169
return transientOperationalKeypair->ECDSA_sign_msg (message.data (), message.size (), outSignature);
161
170
}
@@ -251,6 +260,13 @@ CHIP_ERROR PersistentStorageOperationalKeystore::CommitOpKeypairForFabric(Fabric
251
260
return CHIP_NO_ERROR;
252
261
}
253
262
263
+ CHIP_ERROR PersistentStorageOperationalKeystore::ExportOpKeypairForFabric (FabricIndex fabricIndex,
264
+ Crypto::P256SerializedKeypair & outKeypair)
265
+ {
266
+ VerifyOrReturnError (mStorage != nullptr , CHIP_ERROR_INCORRECT_STATE);
267
+ return ExportStoredOpKey (fabricIndex, mStorage , outKeypair);
268
+ }
269
+
254
270
CHIP_ERROR PersistentStorageOperationalKeystore::RemoveOpKeypairForFabric (FabricIndex fabricIndex)
255
271
{
256
272
VerifyOrReturnError (mStorage != nullptr , CHIP_ERROR_INCORRECT_STATE);
@@ -310,4 +326,36 @@ void PersistentStorageOperationalKeystore::ReleaseEphemeralKeypair(Crypto::P256K
310
326
Platform::Delete<Crypto::P256Keypair>(keypair);
311
327
}
312
328
329
+ CHIP_ERROR PersistentStorageOperationalKeystore::MigrateOpKeypairForFabric (FabricIndex fabricIndex,
330
+ OperationalKeystore & operationalKeystore) const
331
+ {
332
+ VerifyOrReturnError (mStorage != nullptr , CHIP_ERROR_INCORRECT_STATE);
333
+ VerifyOrReturnError (IsValidFabricIndex (fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
334
+
335
+ P256SerializedKeypair serializedKeypair;
336
+
337
+ // Do not allow overwriting the existing key and just remove it from the previous Operational Keystore if needed.
338
+ if (!HasOpKeypairForFabric (fabricIndex))
339
+ {
340
+ ReturnErrorOnFailure (operationalKeystore.ExportOpKeypairForFabric (fabricIndex, serializedKeypair));
341
+
342
+ auto operationalKeypair = Platform::MakeUnique<P256Keypair>();
343
+ if (!operationalKeypair)
344
+ {
345
+ return CHIP_ERROR_NO_MEMORY;
346
+ }
347
+
348
+ ReturnErrorOnFailure (operationalKeypair->Deserialize (serializedKeypair));
349
+ ReturnErrorOnFailure (StoreOperationalKey (fabricIndex, mStorage , operationalKeypair.get ()));
350
+
351
+ ReturnErrorOnFailure (operationalKeystore.RemoveOpKeypairForFabric (fabricIndex));
352
+ }
353
+ else if (operationalKeystore.HasOpKeypairForFabric (fabricIndex))
354
+ {
355
+ ReturnErrorOnFailure (operationalKeystore.RemoveOpKeypairForFabric (fabricIndex));
356
+ }
357
+
358
+ return CHIP_NO_ERROR;
359
+ }
360
+
313
361
} // namespace chip
0 commit comments