ACL payload conversion from JSON to CBOR
[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, .flags = 0 };
230                 CborValue cbor =  { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
231                 cbor_parser_init(fsData, fileSize, 0, &parser, &cbor);
232                 CborValue cborValue =  { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
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                 }
254             }
255             // return everything in case rsrcName is NULL
256             else
257             {
258                 *data = fsData;
259                 *size = fileSize;
260             }
261         }
262     }
263     else
264     {
265         OIC_LOG (ERROR, TAG, "Unable to open SVR database to read!! ");
266     }
267
268 exit:
269     if (ps && fp)
270     {
271         ps->close(fp);
272     }
273     return ret;
274 }
275
276 OCStackResult UpdateSecureResourceInPS(const char* rsrcName, const uint8_t* psPayload, size_t psSize)
277 {
278     /*
279      * This function stores cbor payload of each resource by appending resource name.
280      */
281     if (!rsrcName || !*psPayload)
282     {
283         return OC_STACK_INVALID_PARAM;
284     }
285     OCStackResult ret = OC_STACK_ERROR;
286
287     size_t cborSize = 0;
288     uint8_t *dbData = NULL;
289     uint8_t *outPayload = NULL;
290     size_t dbSize = 0;
291
292     ret = GetSecureVirtualDatabaseFromPS(NULL, &dbData, &dbSize);
293     if (dbData && dbSize != 0)
294     {
295         uint8_t size = dbSize + psSize;
296
297         outPayload = (uint8_t *)OICCalloc(1, size);
298         VERIFY_NON_NULL(TAG, outPayload, ERROR);
299
300         CborEncoder encoder = { { .ptr = NULL }, .end = NULL, .added = 0, .flags = 0};
301         cbor_encoder_init(&encoder, outPayload, size, 0);
302         {
303             CborEncoder map = { {.ptr = NULL }, .end = 0, .added = 0, .flags = 0};
304             CborError cborEncoderResult = cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
305             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Creating PS Interface Map.");
306             {
307                 bool found = false;
308                 CborValue cbor = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
309                 CborParser parser = { .end = NULL, .flags = 0 };
310                 cbor_parser_init(dbData, size, 0, &parser, &cbor);
311
312                 CborValue cborValue = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
313                 CborError cborFindResult = CborNoError;
314
315                 if (cbor_value_is_container(&cbor))
316                 {
317                     cborFindResult = cbor_value_enter_container(&cbor, &cborValue);
318                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering PS Interface Map.");
319                 }
320
321                 while (cbor_value_is_valid(&cborValue))
322                 {
323                     char *name = NULL;
324                     size_t len = 0;
325                     cborFindResult = cbor_value_dup_text_string(&cborValue, &name, &len, NULL);
326                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Duplicating Value.");
327                     cborFindResult = cbor_value_advance(&cborValue);
328                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Value.");
329
330                     cborEncoderResult = cbor_encode_text_string(&map, name, strlen(name));
331                     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Copying Text Str Value.");
332
333                     if (strcmp(name, rsrcName) == 0)
334                     {
335                         cborEncoderResult = cbor_encode_byte_string(&map, psPayload, psSize);
336                         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Encoding Byte String.");
337                         found = true;
338                     }
339                     else
340                     {
341                         uint8_t *byteString = NULL;
342                         size_t byteLen = 0;
343                         cborFindResult = cbor_value_dup_byte_string(&cborValue, &byteString, &byteLen, NULL);
344                         VERIFY_SUCCESS(TAG, cborFindResult == CborNoError, ERROR);
345                         if (byteString)
346                         {
347                             cborEncoderResult = cbor_encode_byte_string(&map, byteString, byteLen);
348                             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding value.");
349                         }
350                         OICFree(byteString);
351                     }
352                     OICFree(name);
353                     cbor_value_advance(&cborValue);
354                 }
355
356                 // This is an exception when the value is not stored in the database.
357                 if (!found)
358                 {
359                     cborEncoderResult = cbor_encode_text_string(&map, rsrcName, strlen(rsrcName));
360                     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding value.");
361                     cborEncoderResult = cbor_encode_byte_string(&map, psPayload, psSize);
362                     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed entering byte string.");
363                 }
364             }
365             cborEncoderResult = cbor_encoder_close_container(&encoder, &map);
366             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing container.");
367         }
368         cborSize = encoder.ptr - outPayload;
369     }
370
371     {
372         OCPersistentStorage* ps = SRMGetPersistentStorageHandler();
373         if (ps)
374         {
375             FILE *fp = ps->open(SVR_DB_DAT_FILE_NAME, "w+");
376             if (fp)
377             {
378                 size_t numberItems = ps->write(outPayload, 1, cborSize, fp);
379                 if (cborSize == numberItems)
380                 {
381                     OIC_LOG_V(DEBUG, TAG, "Written %zu bytes into SVR database file", cborSize);
382                     ret = OC_STACK_OK;
383                 }
384                 else
385                 {
386                     OIC_LOG_V(ERROR, TAG, "Failed writing %zu in the database", numberItems);
387                 }
388                 ps->close(fp);
389             }
390             else
391             {
392                 OIC_LOG(ERROR, TAG, "File open failed.");
393             }
394
395         }
396     }
397
398
399 exit:
400     if (dbData)
401     {
402         OICFree(dbData);
403     }
404     if (outPayload)
405     {
406         OICFree(outPayload);
407     }
408
409     return ret;
410 }