Security code comments which are doxygen compliant
[platform/upstream/iotivity.git] / resource / csdk / security / src / psinterface.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20 #ifdef WITH_ARDUINO
21 #define __STDC_LIMIT_MACROS
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include "ocstack.h"
27 #include "logger.h"
28 #include "oic_malloc.h"
29 #include "ocpayload.h"
30 #include "ocpayloadcbor.h"
31 #include "payload_logging.h"
32 #include "cJSON.h"
33 #include "cainterface.h"
34 #include "secureresourcemanager.h"
35 #include "resourcemanager.h"
36 #include "srmresourcestrings.h"
37 #include "srmutility.h"
38
39 #define TAG  "SRM-PSI"
40
41 //SVR database buffer block size
42 const size_t DB_FILE_SIZE_BLOCK = 1023;
43
44 /**
45  * Gets the Secure Virtual Database size.
46  *
47  * @param ps pointer of OCPersistentStorage for the SVR name ("acl", "cred", "pstat" etc).
48  *
49  * @return total size of the SVR database.
50  */
51 static size_t GetSVRDatabaseSize(const OCPersistentStorage* ps)
52 {
53     size_t size = 0;
54     if (!ps)
55     {
56         return size;
57     }
58     size_t bytesRead  = 0;
59     char buffer[DB_FILE_SIZE_BLOCK];
60     FILE* fp = ps->open(SVR_DB_DAT_FILE_NAME, "r");
61     if (fp)
62     {
63         do
64         {
65             bytesRead = ps->read(buffer, 1, DB_FILE_SIZE_BLOCK, fp);
66             size += bytesRead;
67         } while (bytesRead > 0);
68         ps->close(fp);
69     }
70     return size;
71 }
72
73 char* GetSVRDatabase()
74 {
75     char * jsonStr = NULL;
76     FILE * fp = NULL;
77     OCPersistentStorage* ps = SRMGetPersistentStorageHandler();
78     int size = GetSVRDatabaseSize(ps);
79     if (0 == size)
80     {
81         OIC_LOG (ERROR, TAG, "FindSVRDatabaseSize failed");
82         return NULL;
83     }
84
85     if (ps && ps->open)
86     {
87         // Open default SRM database file. An app could change the path for its server.
88         fp = ps->open(SVR_DB_FILE_NAME, "r");
89         if (fp)
90         {
91             jsonStr = (char*)OICMalloc(size + 1);
92             VERIFY_NON_NULL(TAG, jsonStr, FATAL);
93             size_t bytesRead = ps->read(jsonStr, 1, size, fp);
94             jsonStr[bytesRead] = '\0';
95
96             OIC_LOG_V(DEBUG, TAG, "Read %zu bytes from SVR database file", bytesRead);
97             ps->close(fp);
98             fp = NULL;
99         }
100         else
101         {
102             OIC_LOG (ERROR, TAG, "Unable to open SVR database file!!");
103         }
104     }
105
106 exit:
107     if (ps && fp)
108     {
109         ps->close(fp);
110     }
111     return jsonStr;
112 }
113
114 OCStackResult UpdateSVRDatabase(const char* rsrcName, cJSON* jsonObj)
115 {
116     OCStackResult ret = OC_STACK_ERROR;
117     cJSON *jsonSVRDb = NULL;
118     OCPersistentStorage* ps = NULL;
119
120     // Read SVR database from PS
121     char* jsonSVRDbStr = GetSVRDatabase();
122     VERIFY_NON_NULL(TAG,jsonSVRDbStr, ERROR);
123
124     // Use cJSON_Parse to parse the existing SVR database
125     jsonSVRDb = cJSON_Parse(jsonSVRDbStr);
126     VERIFY_NON_NULL(TAG,jsonSVRDb, ERROR);
127
128     OICFree(jsonSVRDbStr);
129     jsonSVRDbStr = NULL;
130
131     //If Cred resource gets updated with empty list then delete the Cred
132     //object from database.
133     if(NULL == jsonObj && (0 == strcmp(rsrcName, OIC_JSON_CRED_NAME)))
134     {
135         cJSON_DeleteItemFromObject(jsonSVRDb, rsrcName);
136     }
137     else if (jsonObj->child )
138     {
139         // Create a duplicate of the JSON object which was passed.
140         cJSON* jsonDuplicateObj = cJSON_Duplicate(jsonObj, 1);
141         VERIFY_NON_NULL(TAG,jsonDuplicateObj, ERROR);
142
143         cJSON* jsonObj = cJSON_GetObjectItem(jsonSVRDb, rsrcName);
144
145         /*
146          ACL, PStat & Doxm resources at least have default entries in the database but
147          Cred resource may have no entries. The first cred resource entry (for provisioning tool)
148          is created when the device is owned by provisioning tool and it's ownerpsk is generated.*/
149         if((strcmp(rsrcName, OIC_JSON_CRED_NAME) == 0 ||
150                 strcmp(rsrcName, OIC_JSON_CRL_NAME) == 0 ||
151                 strcmp(rsrcName, OIC_JSON_PCONF_NAME) == 0 ||
152                 strcmp(rsrcName, OIC_JSON_DPAIRING_NAME) == 0) && (!jsonObj))
153         {
154             // Add the fist cred object in existing SVR database json
155             cJSON_AddItemToObject(jsonSVRDb, rsrcName, jsonDuplicateObj->child);
156         }
157         else
158         {
159             VERIFY_NON_NULL(TAG,jsonObj, ERROR);
160
161             // Replace the modified json object in existing SVR database json
162             cJSON_ReplaceItemInObject(jsonSVRDb, rsrcName, jsonDuplicateObj->child);
163         }
164     }
165
166     // Generate string representation of updated SVR database json object
167     jsonSVRDbStr = cJSON_PrintUnformatted(jsonSVRDb);
168     VERIFY_NON_NULL(TAG,jsonSVRDbStr, ERROR);
169
170     // Update the persistent storage with new SVR database
171     ps = SRMGetPersistentStorageHandler();
172     if (ps && ps->open)
173     {
174         FILE* fp = ps->open(SVR_DB_FILE_NAME, "w");
175         if (fp)
176         {
177             size_t bytesWritten = ps->write(jsonSVRDbStr, 1, strlen(jsonSVRDbStr), fp);
178             if (bytesWritten == strlen(jsonSVRDbStr))
179             {
180                 ret = OC_STACK_OK;
181             }
182             OIC_LOG_V(DEBUG, TAG, "Written %zu bytes into SVR database file", bytesWritten);
183             ps->close(fp);
184             fp = NULL;
185         }
186         else
187         {
188             OIC_LOG (ERROR, TAG, "Unable to open SVR database file!! ");
189         }
190     }
191
192 exit:
193     OICFree(jsonSVRDbStr);
194     cJSON_Delete(jsonSVRDb);
195
196     return ret;
197 }
198
199 OCStackResult GetSecureVirtualDatabaseFromPS(const char *rsrcName, uint8_t **data, size_t *size)
200 {
201     if (!data || !size)
202     {
203         return OC_STACK_INVALID_PARAM;
204     }
205     OCStackResult ret = OC_STACK_ERROR;
206     *data = NULL;
207
208      FILE *fp = NULL;
209     size_t fileSize = 0;
210
211     OCPersistentStorage *ps = SRMGetPersistentStorageHandler();
212     VERIFY_NON_NULL(TAG, ps, ERROR);
213
214     fileSize = GetSVRDatabaseSize(ps);
215     if (fileSize != 0)
216     {
217         OIC_LOG_V(DEBUG, TAG, "File Read Size: %zu", fileSize);
218         uint8_t *fsData = (uint8_t *)OICCalloc(1, fileSize);
219         VERIFY_NON_NULL(TAG, fsData, ERROR);
220
221         FILE *fp = ps->open(SVR_DB_DAT_FILE_NAME, "r");
222         VERIFY_NON_NULL(TAG, fp, ERROR);
223         size_t itemsRead = ps->read(fsData, 1, fileSize, fp);
224         if (itemsRead == fileSize)
225         {
226             VERIFY_NON_NULL(TAG, fsData, ERROR);
227             if (rsrcName != NULL)
228             {
229                 CborParser parser = { .end = NULL };
230                 CborValue cbor =  { .parser = NULL };
231                 cbor_parser_init(fsData, fileSize, 0, &parser, &cbor);
232                 CborValue cborValue =  { .parser = NULL };
233                 CborError cborFindResult = cbor_value_enter_container(&cbor, &cborValue);
234
235                 while (cbor_value_is_valid(&cborValue))
236                 {
237                     char *name = NULL;
238                     size_t len = 0;
239                     cborFindResult = cbor_value_dup_text_string(&cborValue, &name, &len, NULL);
240                     VERIFY_SUCCESS(TAG, cborFindResult == CborNoError, ERROR);
241                     cborFindResult = cbor_value_advance(&cborValue);
242                     VERIFY_SUCCESS(TAG, cborFindResult == CborNoError, ERROR);
243                     if (strcmp(name, rsrcName) == 0)
244                     {
245                         cborFindResult = cbor_value_dup_byte_string(&cborValue, data, size, NULL);
246                         VERIFY_SUCCESS(TAG, cborFindResult == CborNoError, ERROR);
247                         ret = OC_STACK_OK;
248                         OICFree(fsData);
249                         OICFree(name);
250                         goto exit;
251                     }
252                     OICFree(name);
253                     cborFindResult = cbor_value_advance(&cborValue);
254                     VERIFY_SUCCESS(TAG, cborFindResult == CborNoError, ERROR);
255                 }
256             }
257             // return everything in case rsrcName is NULL
258             else
259             {
260                 *data = fsData;
261                 *size = fileSize;
262             }
263         }
264     }
265     else
266     {
267         OIC_LOG(ERROR, TAG, "Unable to open SVR database to read!! ");
268     }
269
270 exit:
271     if (ps && fp)
272     {
273         ps->close(fp);
274     }
275     return ret;
276 }
277
278 OCStackResult UpdateSecureResourceInPS(const char* rsrcName, const uint8_t* psPayload, size_t psSize)
279 {
280     /*
281      * This function stores cbor payload of each resource by appending resource name.
282      */
283     if (!rsrcName || !psPayload)
284     {
285         return OC_STACK_INVALID_PARAM;
286     }
287     OCStackResult ret = OC_STACK_ERROR;
288
289     size_t cborSize = 0;
290     uint8_t *dbData = NULL;
291     uint8_t *outPayload = NULL;
292     size_t dbSize = 0;
293
294     ret = GetSecureVirtualDatabaseFromPS(NULL, &dbData, &dbSize);
295     if (dbData && dbSize != 0)
296     {
297         uint8_t size = dbSize + psSize;
298
299         outPayload = (uint8_t *)OICCalloc(1, size);
300         VERIFY_NON_NULL(TAG, outPayload, ERROR);
301
302         CborEncoder encoder = { { .ptr = NULL }, .end = 0 };
303         cbor_encoder_init(&encoder, outPayload, size, 0);
304         {
305             CborEncoder map = { {.ptr = NULL }, .end = 0 };
306             CborError cborEncoderResult = cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
307             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Creating PS Interface Map.");
308             {
309                 bool found = false;
310                 CborValue cbor = { .parser = NULL };
311                 CborParser parser = { .end = NULL };
312                 cbor_parser_init(dbData, size, 0, &parser, &cbor);
313
314                 CborValue cborValue = { .parser = NULL };
315                 CborError cborFindResult = CborNoError;
316
317                 if (cbor_value_is_container(&cbor))
318                 {
319                     cborFindResult = cbor_value_enter_container(&cbor, &cborValue);
320                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering PS Interface Map.");
321                 }
322
323                 while (cbor_value_is_valid(&cborValue))
324                 {
325                     char *name = NULL;
326                     size_t len = 0;
327                     cborFindResult = cbor_value_dup_text_string(&cborValue, &name, &len, NULL);
328                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Duplicating Value.");
329                     cborFindResult = cbor_value_advance(&cborValue);
330                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Value.");
331
332                     cborEncoderResult = cbor_encode_text_string(&map, name, strlen(name));
333                     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Copying Text Str Value.");
334
335                     if (strcmp(name, rsrcName) == 0)
336                     {
337                         cborEncoderResult = cbor_encode_byte_string(&map, psPayload, psSize);
338                         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Encoding Byte String.");
339                         found = true;
340                     }
341                     else
342                     {
343                         uint8_t *byteString = NULL;
344                         size_t byteLen = 0;
345                         cborFindResult = cbor_value_dup_byte_string(&cborValue, &byteString, &byteLen, NULL);
346                         VERIFY_SUCCESS(TAG, cborFindResult == CborNoError, ERROR);
347                         if (byteString)
348                         {
349                             cborEncoderResult = cbor_encode_byte_string(&map, byteString, byteLen);
350                             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding value.");
351                         }
352                         OICFree(byteString);
353                     }
354                     OICFree(name);
355                     cbor_value_advance(&cborValue);
356                 }
357
358                 // This is an exception when the value is not stored in the database.
359                 if (!found)
360                 {
361                     cborEncoderResult = cbor_encode_text_string(&map, rsrcName, strlen(rsrcName));
362                     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding value.");
363                     cborEncoderResult = cbor_encode_byte_string(&map, psPayload, psSize);
364                     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed entering byte string.");
365                 }
366             }
367             cborEncoderResult = cbor_encoder_close_container(&encoder, &map);
368             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing container.");
369         }
370         cborSize = encoder.ptr - outPayload;
371     }
372
373     {
374         OCPersistentStorage* ps = SRMGetPersistentStorageHandler();
375         if (ps)
376         {
377             FILE *fp = ps->open(SVR_DB_DAT_FILE_NAME, "w+");
378             if (fp)
379             {
380                 size_t numberItems = ps->write(outPayload, 1, cborSize, fp);
381                 if (cborSize == numberItems)
382                 {
383                     OIC_LOG_V(DEBUG, TAG, "Written %zu bytes into SVR database file", cborSize);
384                     ret = OC_STACK_OK;
385                 }
386                 else
387                 {
388                     OIC_LOG_V(ERROR, TAG, "Failed writing %zu in the database", numberItems);
389                 }
390                 ps->close(fp);
391             }
392             else
393             {
394                 OIC_LOG(ERROR, TAG, "File open failed.");
395             }
396
397         }
398     }
399
400
401 exit:
402     if (dbData)
403     {
404         OICFree(dbData);
405     }
406     if (outPayload)
407     {
408         OICFree(outPayload);
409     }
410
411     return ret;
412 }