Line data Source code
1 : /*
2 : * Copyright (c) 2022 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <cstring>
19 :
20 : #include <lib/core/CHIPError.h>
21 : #include <lib/core/CHIPPersistentStorageDelegate.h>
22 : #include <lib/support/logging/CHIPLogging.h>
23 :
24 : #include "PersistentStorageAudit.h"
25 :
26 : #ifdef NL_TEST_ASSERT
27 : #undef NL_TEST_ASSERT
28 : #endif
29 :
30 : #define NL_TEST_ASSERT(inSuite, inCondition) \
31 : do \
32 : { \
33 : (inSuite)->performedAssertions += 1; \
34 : \
35 : if (!(inCondition)) \
36 : { \
37 : ChipLogError(Automation, "%s:%u: assertion failed: \"%s\"", __FILE__, __LINE__, #inCondition); \
38 : (inSuite)->failedAssertions += 1; \
39 : (inSuite)->flagError = true; \
40 : } \
41 : } while (0)
42 :
43 : namespace chip {
44 : namespace audit {
45 :
46 : // The following test is a copy of `src/lib/support/tests/TestTestPersistentStorageDelegate.cpp` 's
47 : // `TestBasicApi()` test. It has to be copied since we currently are not setup to
48 : // run on-device unit tests at large on all embedded platforms part of the SDK.
49 0 : bool ExecutePersistentStorageApiAudit(PersistentStorageDelegate & storage)
50 : {
51 : struct fakeTestSuite
52 : {
53 : int performedAssertions = 0;
54 : int failedAssertions = 0;
55 : bool flagError = false;
56 0 : } theSuite;
57 0 : auto * inSuite = &theSuite;
58 :
59 : static const char kLongKeyString[] = "aKeyThatIsExactlyMaxKeyLengthhhh";
60 : // Start fresh.
61 0 : (void) storage.SyncDeleteKeyValue("roboto");
62 0 : (void) storage.SyncDeleteKeyValue("key2");
63 0 : (void) storage.SyncDeleteKeyValue("key3");
64 0 : (void) storage.SyncDeleteKeyValue("key4");
65 0 : (void) storage.SyncDeleteKeyValue("keyDOES_NOT_EXIST");
66 0 : (void) storage.SyncDeleteKeyValue(kLongKeyString);
67 :
68 : // ========== Start of actual audit from TestTestPersistentStorageDelegate.cpp =========
69 :
70 : uint8_t buf[16];
71 0 : const uint16_t actualSizeOfBuf = static_cast<uint16_t>(sizeof(buf));
72 0 : uint16_t size = actualSizeOfBuf;
73 :
74 : // Key not there
75 : CHIP_ERROR err;
76 0 : memset(&buf[0], 0, sizeof(buf));
77 0 : size = actualSizeOfBuf;
78 0 : err = storage.SyncGetKeyValue("roboto", &buf[0], size);
79 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
80 0 : NL_TEST_ASSERT(inSuite, size == actualSizeOfBuf);
81 :
82 0 : err = storage.SyncDeleteKeyValue("roboto");
83 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
84 :
85 : // Add basic key, read it back, erase it
86 : static const char kStringValue1[] = "abcd";
87 0 : err = storage.SyncSetKeyValue("roboto", kStringValue1, static_cast<uint16_t>(strlen(kStringValue1)));
88 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
89 :
90 0 : memset(&buf[0], 0, sizeof(buf));
91 0 : size = actualSizeOfBuf;
92 0 : err = storage.SyncGetKeyValue("roboto", &buf[0], size);
93 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
94 0 : NL_TEST_ASSERT(inSuite, size == strlen(kStringValue1));
95 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], kStringValue1, strlen(kStringValue1)));
96 :
97 0 : err = storage.SyncDeleteKeyValue("roboto");
98 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
99 :
100 0 : memset(&buf[0], 0, sizeof(buf));
101 0 : size = actualSizeOfBuf;
102 0 : err = storage.SyncGetKeyValue("roboto", &buf[0], size);
103 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
104 0 : NL_TEST_ASSERT(inSuite, size == actualSizeOfBuf);
105 :
106 : // Validate adding 2 different keys
107 : static const char kStringValue2[] = "0123abcd";
108 : static const char kStringValue3[] = "cdef89";
109 0 : err = storage.SyncSetKeyValue("key2", kStringValue2, static_cast<uint16_t>(strlen(kStringValue2)));
110 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
111 :
112 0 : err = storage.SyncSetKeyValue("key3", kStringValue3, static_cast<uint16_t>(strlen(kStringValue3)));
113 0 : NL_TEST_ASSERT(inSuite, storage.SyncDoesKeyExist("key3"));
114 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
115 :
116 : // Read them back
117 :
118 : uint8_t all_zeroes[sizeof(buf)];
119 0 : memset(&all_zeroes[0], 0, sizeof(all_zeroes));
120 :
121 0 : memset(&buf[0], 0, sizeof(buf));
122 0 : size = actualSizeOfBuf;
123 0 : err = storage.SyncGetKeyValue("key2", &buf[0], size);
124 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
125 0 : NL_TEST_ASSERT(inSuite, size == strlen(kStringValue2));
126 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], kStringValue2, strlen(kStringValue2)));
127 : // Make sure that there was no buffer overflow during SyncGetKeyValue
128 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[size], &all_zeroes[0], sizeof(buf) - size));
129 :
130 0 : memset(&buf[0], 0, sizeof(buf));
131 0 : size = actualSizeOfBuf;
132 0 : err = storage.SyncGetKeyValue("key3", &buf[0], size);
133 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
134 0 : NL_TEST_ASSERT(inSuite, size == strlen(kStringValue3));
135 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], kStringValue3, strlen(kStringValue3)));
136 : // Make sure that there was no buffer overflow during SyncGetKeyValue
137 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[size], &all_zeroes[0], sizeof(buf) - size));
138 :
139 : // Read providing too small a buffer. Data read up to `size` and nothing more.
140 0 : memset(&buf[0], 0, sizeof(buf));
141 0 : size = static_cast<uint16_t>(strlen(kStringValue2) - 1);
142 0 : uint16_t sizeBeforeGetKeyValueCall = size;
143 0 : err = storage.SyncGetKeyValue("key2", &buf[0], size);
144 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BUFFER_TOO_SMALL);
145 0 : NL_TEST_ASSERT(inSuite, size == sizeBeforeGetKeyValueCall);
146 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], kStringValue2, size));
147 : // Make sure that there was no buffer overflow during SyncGetKeyValue
148 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[size], &all_zeroes[0], sizeof(buf) - size));
149 :
150 : // Read in too small a buffer, which is nullptr and size == 0: check CHIP_ERROR_BUFFER_TOO_SMALL is given.
151 0 : memset(&buf[0], 0, sizeof(buf));
152 0 : size = 0;
153 0 : sizeBeforeGetKeyValueCall = size;
154 0 : err = storage.SyncGetKeyValue("key2", nullptr, size);
155 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BUFFER_TOO_SMALL);
156 0 : NL_TEST_ASSERT(inSuite, size != strlen(kStringValue2));
157 0 : NL_TEST_ASSERT(inSuite, size == sizeBeforeGetKeyValueCall);
158 : // Just making sure that implementation doesn't hold onto reference of previous destination buffer when
159 : // nullptr is provided.
160 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], &all_zeroes[0], sizeof(buf)));
161 :
162 : // Read in too small a buffer, which is nullptr and size != 0: error
163 0 : size = static_cast<uint16_t>(strlen(kStringValue2) - 1);
164 0 : sizeBeforeGetKeyValueCall = size;
165 0 : err = storage.SyncGetKeyValue("key2", nullptr, size);
166 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT);
167 0 : NL_TEST_ASSERT(inSuite, size == sizeBeforeGetKeyValueCall);
168 : // Just making sure that implementation doesn't hold onto reference of previous destination buffer when
169 : // nullptr is provided.
170 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], &all_zeroes[0], sizeof(buf)));
171 :
172 : // When key not found, size is not touched.
173 0 : size = actualSizeOfBuf;
174 0 : err = storage.SyncGetKeyValue("keyDOES_NOT_EXIST", &buf[0], size);
175 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
176 0 : NL_TEST_ASSERT(inSuite, actualSizeOfBuf == size);
177 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], &all_zeroes[0], sizeof(buf)));
178 :
179 0 : size = 0;
180 0 : err = storage.SyncGetKeyValue("keyDOES_NOT_EXIST", nullptr, size);
181 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
182 0 : NL_TEST_ASSERT(inSuite, 0 == size);
183 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], &all_zeroes[0], sizeof(buf)));
184 :
185 : // Even when key not found, cannot pass nullptr with size != 0.
186 0 : size = actualSizeOfBuf;
187 0 : err = storage.SyncGetKeyValue("keyDOES_NOT_EXIST", nullptr, size);
188 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT);
189 0 : NL_TEST_ASSERT(inSuite, actualSizeOfBuf == size);
190 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], &all_zeroes[0], size));
191 :
192 : // Attempt an empty key write with either nullptr or zero size works
193 0 : err = storage.SyncSetKeyValue("key2", kStringValue2, 0);
194 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
195 0 : NL_TEST_ASSERT(inSuite, storage.SyncDoesKeyExist("key2"));
196 :
197 0 : size = 0;
198 0 : err = storage.SyncGetKeyValue("key2", &buf[0], size);
199 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
200 0 : NL_TEST_ASSERT(inSuite, size == 0);
201 :
202 0 : size = 0;
203 0 : err = storage.SyncGetKeyValue("key2", nullptr, size);
204 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
205 0 : NL_TEST_ASSERT(inSuite, size == 0);
206 :
207 0 : size = actualSizeOfBuf;
208 0 : err = storage.SyncGetKeyValue("key2", &buf[0], size);
209 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
210 0 : NL_TEST_ASSERT(inSuite, size == 0);
211 :
212 0 : err = storage.SyncSetKeyValue("key2", nullptr, 0);
213 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
214 0 : NL_TEST_ASSERT(inSuite, storage.SyncDoesKeyExist("key2"));
215 :
216 0 : size = 0;
217 0 : err = storage.SyncGetKeyValue("key2", &buf[0], size);
218 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
219 0 : NL_TEST_ASSERT(inSuite, size == 0);
220 :
221 : // Failure to set key if buffer is nullptr and size != 0
222 0 : size = 10;
223 0 : err = storage.SyncSetKeyValue("key4", nullptr, size);
224 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT);
225 0 : NL_TEST_ASSERT(inSuite, !storage.SyncDoesKeyExist("key4"));
226 :
227 : // Can delete empty key
228 0 : err = storage.SyncDeleteKeyValue("key2");
229 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
230 :
231 0 : NL_TEST_ASSERT(inSuite, !storage.SyncDoesKeyExist("key2"));
232 :
233 0 : size = actualSizeOfBuf;
234 0 : err = storage.SyncGetKeyValue("key2", &buf[0], size);
235 0 : NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
236 0 : NL_TEST_ASSERT(inSuite, size == actualSizeOfBuf);
237 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], &all_zeroes[0], size));
238 :
239 : // Using key and value with base64 symbols
240 : static const char kBase64SymbolsKey[] = "key+/=";
241 : static const char kBase64SymbolValues[] = "value+/=";
242 0 : err = storage.SyncSetKeyValue(kBase64SymbolsKey, kBase64SymbolValues, static_cast<uint16_t>(strlen(kBase64SymbolValues)));
243 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
244 :
245 0 : memset(&buf[0], 0, sizeof(buf));
246 0 : size = actualSizeOfBuf;
247 0 : err = storage.SyncGetKeyValue(kBase64SymbolsKey, &buf[0], size);
248 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
249 0 : NL_TEST_ASSERT(inSuite, size == strlen(kBase64SymbolValues));
250 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], kBase64SymbolValues, strlen(kBase64SymbolValues)));
251 : // Make sure that there was no buffer overflow during SyncGetKeyValue
252 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[size], &all_zeroes[0], sizeof(buf) - size));
253 :
254 0 : err = storage.SyncDeleteKeyValue(kBase64SymbolsKey);
255 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
256 0 : NL_TEST_ASSERT(inSuite, !storage.SyncDoesKeyExist(kBase64SymbolsKey));
257 :
258 : // Try using key that is a size that equals PersistentStorageDelegate::kKeyLengthMax
259 : char longKeyString[PersistentStorageDelegate::kKeyLengthMax + 1];
260 0 : memset(&longKeyString, 'X', PersistentStorageDelegate::kKeyLengthMax);
261 0 : longKeyString[sizeof(longKeyString) - 1] = '\0';
262 : // strlen() is not compile time so we just have this runtime assert that should aways pass as a sanity check.
263 0 : NL_TEST_ASSERT(inSuite, strlen(longKeyString) == PersistentStorageDelegate::kKeyLengthMax);
264 :
265 0 : err = storage.SyncSetKeyValue(longKeyString, kStringValue2, static_cast<uint16_t>(strlen(kStringValue2)));
266 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
267 :
268 0 : memset(&buf[0], 0, sizeof(buf));
269 0 : size = actualSizeOfBuf;
270 0 : err = storage.SyncGetKeyValue(longKeyString, &buf[0], size);
271 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
272 0 : NL_TEST_ASSERT(inSuite, size == strlen(kStringValue2));
273 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[0], kStringValue2, strlen(kStringValue2)));
274 : // Make sure that there was no buffer overflow during SyncGetKeyValue
275 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&buf[size], &all_zeroes[0], sizeof(buf) - size));
276 :
277 0 : NL_TEST_ASSERT(inSuite, storage.SyncDoesKeyExist(longKeyString));
278 :
279 0 : err = storage.SyncDeleteKeyValue(longKeyString);
280 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
281 0 : NL_TEST_ASSERT(inSuite, !storage.SyncDoesKeyExist(longKeyString));
282 :
283 0 : constexpr size_t kMaxCHIPCertLength = 400; // From credentials/CHIPCert.h and spec
284 : uint8_t largeBuffer[kMaxCHIPCertLength];
285 0 : memset(&largeBuffer, 'X', sizeof(largeBuffer));
286 : uint8_t largeBufferForCheck[sizeof(largeBuffer)];
287 0 : memcpy(largeBufferForCheck, largeBuffer, sizeof(largeBuffer));
288 :
289 0 : err = storage.SyncSetKeyValue(longKeyString, largeBuffer, static_cast<uint16_t>(sizeof(largeBuffer)));
290 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
291 :
292 0 : memset(&largeBuffer, 0, sizeof(largeBuffer));
293 0 : size = static_cast<uint16_t>(sizeof(largeBuffer));
294 0 : err = storage.SyncGetKeyValue(longKeyString, &largeBuffer[0], size);
295 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
296 0 : NL_TEST_ASSERT(inSuite, size == static_cast<uint16_t>(sizeof(largeBuffer)));
297 0 : NL_TEST_ASSERT(inSuite, 0 == memcmp(&largeBuffer, largeBufferForCheck, sizeof(largeBuffer)));
298 :
299 0 : err = storage.SyncDeleteKeyValue(longKeyString);
300 0 : NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
301 :
302 : // Cleaning up
303 0 : (void) storage.SyncDeleteKeyValue("roboto");
304 0 : (void) storage.SyncDeleteKeyValue("key2");
305 0 : (void) storage.SyncDeleteKeyValue("key3");
306 0 : (void) storage.SyncDeleteKeyValue("key4");
307 0 : (void) storage.SyncDeleteKeyValue(kBase64SymbolsKey);
308 0 : (void) storage.SyncDeleteKeyValue(kLongKeyString);
309 :
310 : // ========== End of code from TestTestPersistentStorageDelegate.cpp =========
311 0 : if (inSuite->flagError)
312 : {
313 0 : ChipLogError(Automation,
314 : "==== PersistentStorageDelegate API audit: FAILED: %d/%d failed assertions ====", inSuite->failedAssertions,
315 : inSuite->performedAssertions);
316 0 : return false;
317 : }
318 :
319 0 : ChipLogError(Automation, "==== PersistentStorageDelegate API audit: SUCCESS ====");
320 0 : return true;
321 : }
322 :
323 0 : bool ExecutePersistentStorageLoadTestAudit(PersistentStorageDelegate & storage)
324 : {
325 : (void) storage;
326 0 : ChipLogError(Automation, "==== PersistentStorageDelegate load test audit: SUCCESS ====");
327 0 : return true;
328 : }
329 :
330 : } // namespace audit
331 : } // namespace chip
|