Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / EFR32 / GroupKeyStoreImpl.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019 Nest Labs, Inc.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 /**
20  *    @file
21  *          Provides an implementation of the CHIP GroupKeyStore interface
22  *          for platforms based on the Silicon Labs SDK.
23  */
24 /* this file behaves like a config.h, comes first */
25 #include <platform/internal/CHIPDeviceLayerInternal.h>
26
27 #include <platform/EFR32/GroupKeyStoreImpl.h>
28
29 using namespace ::chip;
30 using namespace ::chip::Profiles::Security::AppKeys;
31
32 namespace chip {
33 namespace DeviceLayer {
34 namespace Internal {
35
36 CHIP_ERROR GroupKeyStoreImpl::RetrieveGroupKey(uint32_t keyId, ChipGroupKey & key)
37 {
38     CHIP_ERROR err;
39
40     // Iterate over all the GroupKey nvm3 records looking for a matching key...
41     err = ForEachRecord(kConfigKey_GroupKeyBase, kConfigKey_GroupKeyMax, false,
42                         [keyId, &key](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
43                             CHIP_ERROR err2;
44                             size_t keyLen;
45                             uint8_t buf[kMaxEncodedKeySize]; // (buf length == 45 bytes)
46                             uint32_t curKeyId;
47
48                             // Read the nvm3 obj binary data data into the buffer.
49                             err2 = ReadConfigValueBin(nvm3Key, buf, sizeof(buf), keyLen);
50
51                             // Decode the CHIP key id for the current key.
52                             err2 = DecodeGroupKeyId(buf, keyLen, curKeyId);
53                             SuccessOrExit(err2);
54
55                             // If it matches the key we're looking for...
56                             if (curKeyId == keyId)
57                             {
58                                 // Decode the associated key data.
59                                 err2 = DecodeGroupKey(buf, keyLen, key);
60                                 SuccessOrExit(err2);
61
62                                 // End the iteration by returning a CHIP_END_OF_INPUT result.
63                                 ExitNow(err2 = CHIP_END_OF_INPUT);
64                             }
65
66                         exit:
67                             return err2;
68                         });
69
70     // Modify error code for return.
71     switch (err)
72     {
73     case CHIP_END_OF_INPUT:
74         err = CHIP_NO_ERROR; // Match found.
75         break;
76     case CHIP_NO_ERROR:
77         err = CHIP_ERROR_KEY_NOT_FOUND; // Match not found.
78         break;
79     default:
80         break;
81     }
82
83     return err;
84 }
85
86 CHIP_ERROR GroupKeyStoreImpl::StoreGroupKey(const ChipGroupKey & key)
87 {
88     CHIP_ERROR err;
89
90     // Delete any existing group key with the same id (this may or may not exit).
91     DeleteGroupKey(key.KeyId); // no error checking here.
92
93     // Iterate over all the GroupKey nvm3 records looking for the first
94     // empty nvm3 key where we can store the data. (Note- use arg addNewrecord=true)
95     err = ForEachRecord(kConfigKey_GroupKeyBase, kConfigKey_GroupKeyMax, true,
96                         [&key](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
97                             CHIP_ERROR err2;
98                             size_t keyLen;
99                             uint8_t buf[kMaxEncodedKeySize]; // (buf length == 45 bytes)
100
101                             // Encode the key for storage in an nvm3 record.
102                             err2 = EncodeGroupKey(key, buf, sizeof(buf), keyLen);
103                             SuccessOrExit(err2);
104
105                             // Write the encoded binary data into the nvm3 object.
106                             err2 = WriteConfigValueBin(nvm3Key, buf, keyLen);
107                             SuccessOrExit(err2);
108
109                             // End the iteration by returning a CHIP_END_OF_INPUT result.
110                             ExitNow(err2 = CHIP_END_OF_INPUT);
111
112                         exit:
113                             return err2;
114                         });
115
116     // Modify error code for return.
117     switch (err)
118     {
119     case CHIP_END_OF_INPUT:
120         err = CHIP_NO_ERROR; // Key entry was stored.
121         break;
122     case CHIP_NO_ERROR:
123         err = CHIP_ERROR_KEY_NOT_FOUND; // Key entry was not stored.
124         break;
125     default:
126         break;
127     }
128
129     if (err == CHIP_NO_ERROR)
130     {
131 #if CHIP_PROGRESS_LOGGING
132         {
133             char extraKeyInfo[32];
134             if (ChipKeyId::IsAppEpochKey(key.KeyId))
135             {
136                 snprintf(extraKeyInfo, sizeof(extraKeyInfo), ", start time %" PRId32, key.StartTime);
137             }
138             else if (ChipKeyId::IsAppGroupMasterKey(key.KeyId))
139             {
140                 snprintf(extraKeyInfo, sizeof(extraKeyInfo), ", global id 0x%08" PRIX32, key.GlobalId);
141             }
142             else
143             {
144                 extraKeyInfo[0] = 0;
145             }
146
147 #if CHIP_CONFIG_SECURITY_TEST_MODE
148             ChipLogProgress(SecurityManager,
149                             "GroupKeyStore: storing key 0x%08" PRIX32 " (%s), len %" PRId8 ", data 0x%02" PRIX8 "...%s", key.KeyId,
150                             ChipKeyId::DescribeKey(key.KeyId), key.KeyLen, key.Key[0], extraKeyInfo);
151 #else
152             ChipLogProgress(SecurityManager, "GroupKeyStore: storing key 0x%08" PRIX32 " (%s), len %" PRId8 "%s", key.KeyId,
153                             ChipKeyId::DescribeKey(key.KeyId), key.KeyLen, extraKeyInfo);
154 #endif
155         }
156
157 #endif // CHIP_PROGRESS_LOGGING
158     }
159
160     return err;
161 }
162
163 CHIP_ERROR GroupKeyStoreImpl::DeleteGroupKey(uint32_t keyId)
164 {
165     CHIP_ERROR err;
166
167     // Iterate over all the GroupKey nvm3 records looking for a matching key...
168     err = ForEachRecord(kConfigKey_GroupKeyBase, kConfigKey_GroupKeyMax, false,
169                         [keyId](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
170                             CHIP_ERROR err2;
171                             size_t keyLen;
172                             uint8_t buf[kMaxEncodedKeySize]; // (buf length == 45 bytes)
173                             uint32_t curKeyId;
174
175                             // Read the nvm3 obj binary data data into the buffer.
176                             err2 = ReadConfigValueBin(nvm3Key, buf, sizeof(buf), keyLen);
177                             SuccessOrExit(err2);
178
179                             // Decode the CHIP key id for the current group key.
180                             err2 = DecodeGroupKeyId(buf, keyLen, curKeyId);
181                             SuccessOrExit(err2);
182
183                             // If it matches the key we are looking for, delete the nvm3 record.
184                             if (curKeyId == keyId)
185                             {
186                                 err2 = ClearConfigValue(nvm3Key);
187                                 ChipLogProgress(DeviceLayer, "GroupKeyStore: deleting key 0x%08" PRIX32, curKeyId);
188
189                                 // End the iteration by returning a CHIP_END_OF_INPUT result.
190                                 ExitNow(err2 = CHIP_END_OF_INPUT);
191                             }
192
193                         exit:
194                             return err2;
195                         });
196
197     // Modify error code for return.
198     switch (err)
199     {
200     case CHIP_END_OF_INPUT:
201         err = CHIP_NO_ERROR; // Key entry was deleted.
202         break;
203     case CHIP_NO_ERROR:
204         err = CHIP_ERROR_KEY_NOT_FOUND; // Key entry was not deleted.
205         break;
206     default:
207         break;
208     }
209
210     return err;
211 }
212
213 CHIP_ERROR GroupKeyStoreImpl::DeleteGroupKeysOfAType(uint32_t keyType)
214 {
215     CHIP_ERROR err;
216
217     // Iterate over all the GroupKey nvm3 records looking for a matching key...
218     err = ForEachRecord(kConfigKey_GroupKeyBase, kConfigKey_GroupKeyMax, false,
219                         [keyType](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
220                             CHIP_ERROR err2;
221                             size_t keyLen;
222                             uint8_t buf[kMaxEncodedKeySize]; // (buf length == 45 bytes)
223                             uint32_t curKeyId;
224
225                             // Read the nvm3 obj binary data data into the buffer.
226                             err2 = ReadConfigValueBin(nvm3Key, buf, sizeof(buf), keyLen);
227                             SuccessOrExit(err2);
228
229                             // Decode the CHIP key id for the current group key.
230                             err2 = DecodeGroupKeyId(buf, keyLen, curKeyId);
231                             SuccessOrExit(err2);
232
233                             // If the current key matches the type we are looking for, delete the nvm3 record.
234                             if (ChipKeyId::GetType(curKeyId) == keyType)
235                             {
236                                 err2 = ClearConfigValue(nvm3Key);
237                                 ChipLogProgress(DeviceLayer, "GroupKeyStore: deleting key 0x%08" PRIX32, curKeyId);
238                             }
239
240                         exit:
241                             return err2;
242                         });
243
244     return err;
245 }
246
247 CHIP_ERROR GroupKeyStoreImpl::EnumerateGroupKeys(uint32_t keyType, uint32_t * keyIds, uint8_t keyIdsArraySize, uint8_t & keyCount)
248 {
249     CHIP_ERROR err;
250
251     keyCount = 0;
252
253     // Iterate over all the GroupKey records looking for keys of the specified type...
254     err = ForEachRecord(kConfigKey_GroupKeyBase, kConfigKey_GroupKeyMax, false,
255                         [keyType, keyIds, keyIdsArraySize, &keyCount](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
256                             CHIP_ERROR err2;
257                             size_t keyLen;
258                             uint8_t buf[kMaxEncodedKeySize]; // (buf length == 45 bytes)
259                             uint32_t curKeyId;
260
261                             // Read the nvm3 obj binary data data into the buffer.
262                             err2 = ReadConfigValueBin(nvm3Key, buf, sizeof(buf), keyLen);
263                             SuccessOrExit(err2);
264
265                             // Decode the CHIP key id for the current group key.
266                             err2 = DecodeGroupKeyId(buf, keyLen, curKeyId);
267                             SuccessOrExit(err2);
268
269                             // If the current key matches the type we're looking for, add it to the keyIds array.
270                             if ((keyType == ChipKeyId::kType_None) || (ChipKeyId::GetType(curKeyId) == keyType))
271                             {
272                                 keyIds[keyCount++] = curKeyId;
273
274                                 // Stop iterating if there's no more room in the keyIds array.
275                                 VerifyOrExit(keyCount < keyIdsArraySize, err2 = CHIP_ERROR_BUFFER_TOO_SMALL);
276                             }
277
278                         exit:
279                             return err2;
280                         });
281
282     // Simply return a truncated list if there are more matching keys than will fit in the array.
283     if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
284     {
285         err = CHIP_NO_ERROR;
286     }
287
288     return err;
289 }
290
291 CHIP_ERROR GroupKeyStoreImpl::Clear(void)
292 {
293     CHIP_ERROR err;
294
295     // Iterate over all the GroupKey nvm3 records deleting each one...
296     err = ForEachRecord(kConfigKey_GroupKeyBase, kConfigKey_GroupKeyMax, false,
297                         [](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
298                             CHIP_ERROR err2;
299
300                             err2 = ClearConfigValue(nvm3Key);
301                             SuccessOrExit(err2);
302
303                         exit:
304                             return err2;
305                         });
306
307     return err;
308 }
309
310 CHIP_ERROR GroupKeyStoreImpl::RetrieveLastUsedEpochKeyId(void)
311 {
312     CHIP_ERROR err;
313
314     err = ReadConfigValue(kConfigKey_LastUsedEpochKeyId, LastUsedEpochKeyId);
315     if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND)
316     {
317         LastUsedEpochKeyId = ChipKeyId::kNone;
318         err                = CHIP_NO_ERROR;
319     }
320     return err;
321 }
322
323 CHIP_ERROR GroupKeyStoreImpl::StoreLastUsedEpochKeyId(void)
324 {
325     return WriteConfigValue(kConfigKey_LastUsedEpochKeyId, LastUsedEpochKeyId);
326 }
327
328 CHIP_ERROR GroupKeyStoreImpl::Init()
329 {
330     // Nothing to do
331     return CHIP_NO_ERROR;
332 }
333
334 CHIP_ERROR GroupKeyStoreImpl::EncodeGroupKey(const ChipGroupKey & key, uint8_t * buf, size_t bufSize, size_t & encodedKeyLen)
335 {
336     CHIP_ERROR err = CHIP_NO_ERROR;
337     uint8_t * p    = buf;
338
339     VerifyOrExit(bufSize >= kFixedEncodedKeySize + key.KeyLen, err = CHIP_ERROR_BUFFER_TOO_SMALL);
340
341     Encoding::LittleEndian::Write32(p, key.KeyId);
342     Encoding::LittleEndian::Write32(p, key.StartTime);
343     Encoding::Write8(p, key.KeyLen);
344     memcpy(p, key.Key, key.KeyLen);
345     p += key.KeyLen;
346
347     encodedKeyLen = p - buf;
348
349 exit:
350     return err;
351 }
352
353 CHIP_ERROR GroupKeyStoreImpl::DecodeGroupKeyId(const uint8_t * encodedKey, size_t encodedKeyLen, uint32_t & keyId)
354 {
355     CHIP_ERROR err = CHIP_NO_ERROR;
356
357     VerifyOrExit(encodedKeyLen >= kFixedEncodedKeySize, err = CHIP_ERROR_INVALID_ARGUMENT);
358
359     keyId = Encoding::LittleEndian::Get32(encodedKey);
360
361 exit:
362     return err;
363 }
364
365 CHIP_ERROR GroupKeyStoreImpl::DecodeGroupKey(const uint8_t * encodedKey, size_t encodedKeyLen, ChipGroupKey & key)
366 {
367     CHIP_ERROR err    = CHIP_NO_ERROR;
368     const uint8_t * p = encodedKey;
369
370     VerifyOrExit(encodedKeyLen >= kFixedEncodedKeySize, err = CHIP_ERROR_INVALID_ARGUMENT);
371
372     key.KeyId     = Encoding::LittleEndian::Read32(p);
373     key.StartTime = Encoding::LittleEndian::Read32(p);
374     key.KeyLen    = Encoding::Read8(p);
375
376     VerifyOrExit(encodedKeyLen >= kFixedEncodedKeySize + key.KeyLen, err = CHIP_ERROR_INVALID_ARGUMENT);
377
378     memcpy(key.Key, p, key.KeyLen);
379
380 exit:
381     return err;
382 }
383
384 } // namespace Internal
385 } // namespace DeviceLayer
386 } // namespace chip