Security CBOR conversion
[platform/upstream/iotivity.git] / resource / csdk / security / src / amaclresource.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
21 #include <stdlib.h>
22 #include <string.h>
23 #include "oic_malloc.h"
24 #include "ocpayload.h"
25 #include "payload_logging.h"
26 #include "psinterface.h"
27 #include "resourcemanager.h"
28 #include "utlist.h"
29 #include "srmresourcestrings.h"
30 #include "srmutility.h"
31 #include "amaclresource.h"
32
33 #define TAG  "SRM-AMACL"
34
35 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
36  * The value of payload size is increased until reaching belox max cbor size. */
37 static const uint8_t CBOR_SIZE = 255;
38
39 /* Max cbor size payload. */
40 static const uint16_t CBOR_MAX_SIZE = 4400;
41
42 /** AMACL Map size - Number of mandatory items. */
43 static const uint8_t AMACL_MAP_SIZE = 3;
44
45 static OicSecAmacl_t *gAmacl = NULL;
46 static OCResourceHandle gAmaclHandle = NULL;
47
48 void DeleteAmaclList(OicSecAmacl_t* amacl)
49 {
50     if (amacl)
51     {
52         OicSecAmacl_t *amaclTmp1 = NULL, *amaclTmp2 = NULL;
53         LL_FOREACH_SAFE(amacl, amaclTmp1, amaclTmp2)
54         {
55             LL_DELETE(amacl, amaclTmp1);
56
57             // Clean Resources
58             for (size_t i = 0; i < amaclTmp1->resourcesLen; i++)
59             {
60                 OICFree(amaclTmp1->resources[i]);
61             }
62             OICFree(amaclTmp1->resources);
63
64             // Clean Amss
65             OICFree(amaclTmp1->amss);
66
67             // Clean Owners
68             OICFree(amaclTmp1->owners);
69
70             // Clean Amacl node itself
71             OICFree(amaclTmp1);
72         }
73     }
74 }
75
76 static size_t OicSecAmaclCount(const OicSecAmacl_t *secAmacl)
77 {
78     size_t size = 0;
79     for (const OicSecAmacl_t *amacl = secAmacl; amacl; amacl = amacl->next)
80     {
81         size++;
82     }
83     return size;
84 }
85
86 OCStackResult AmaclToCBORPayload(const OicSecAmacl_t *amaclS, uint8_t **cborPayload,
87                                  size_t *cborSize)
88 {
89     if (NULL == amaclS || NULL == cborPayload || NULL != *cborPayload || NULL == cborSize)
90     {
91         return OC_STACK_INVALID_PARAM;
92     }
93
94     OCStackResult ret = OC_STACK_ERROR;
95     size_t cborLen = *cborSize;
96     if (0 == cborLen)
97     {
98         cborLen = CBOR_SIZE;
99     }
100
101     *cborSize = 0;
102     *cborPayload = NULL;
103
104     CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
105     CborEncoder amaclArray = { {.ptr = NULL }, .end = 0 };
106     int64_t cborEncoderResult = CborNoError;
107
108     const OicSecAmacl_t *amacl = amaclS;
109     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
110     VERIFY_NON_NULL(TAG, outPayload, ERROR);
111     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
112
113     // Create AMACL Array
114     cborEncoderResult |= cbor_encoder_create_array(&encoder, &amaclArray, OicSecAmaclCount(amacl));
115     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMACL Array.");
116
117     while (amacl)
118     {
119         CborEncoder amaclMap = { {.ptr = NULL }, .end = 0 };
120         cborEncoderResult |= cbor_encoder_create_map(&amaclArray, &amaclMap, AMACL_MAP_SIZE);
121         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMACL MAP.");
122
123         // Resources -- Mandatory
124         {
125             CborEncoder resources = { {.ptr = NULL }, .end = 0};
126             cborEncoderResult |= cbor_encode_text_string(&amaclMap, OIC_JSON_RESOURCES_NAME,
127                 strlen(OIC_JSON_RESOURCES_NAME));
128             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Resource Name Tag.");
129             cborEncoderResult |= cbor_encoder_create_array(&amaclMap, &resources, amacl->resourcesLen);
130             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Resource Name Array.");
131
132             for (size_t i = 0; i < amacl->resourcesLen; i++)
133             {
134                 cborEncoderResult |= cbor_encode_text_string(&resources, amacl->resources[i],
135                     strlen(amacl->resources[i]));
136                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Resource Name Value in Array.");
137
138             }
139             cborEncoderResult |= cbor_encoder_close_container(&amaclMap, &resources);
140             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Resource Name ");
141         }
142         // Amss -- Mandatory
143         {
144             CborEncoder amss = { {.ptr = NULL }, .end = 0 };
145             cborEncoderResult |= cbor_encode_text_string(&amaclMap, OIC_JSON_AMSS_NAME,
146                 strlen(OIC_JSON_AMSS_NAME));
147             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMSS Name Tag.");
148             cborEncoderResult |= cbor_encoder_create_array(&amaclMap, &amss, amacl->amssLen);
149             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMSS Name Array.");
150             for (size_t i = 0; i < amacl->amssLen; i++)
151             {
152                 cborEncoderResult |= cbor_encode_byte_string(&amss, amacl->amss[i].id,
153                     sizeof(amacl->amss[i].id));
154                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMSS Name Value.");
155             }
156             cborEncoderResult |= cbor_encoder_close_container(&amaclMap, &amss);
157             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing AMSS Array.");
158         }
159         // Owners -- Mandatory
160         {
161             cborEncoderResult |= cbor_encode_text_string(&amaclMap, OIC_JSON_OWNERS_NAME,
162                 strlen(OIC_JSON_OWNERS_NAME));
163             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Owners Array Tag.");
164             CborEncoder owners = { {.ptr = NULL }, .end = 0};
165             cborEncoderResult |= cbor_encoder_create_array(&amaclMap, &owners, amacl->ownersLen);
166             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Owners Array.");
167
168             for (size_t i = 0; i < amacl->ownersLen; i++)
169             {
170                 cborEncoderResult |= cbor_encode_byte_string(&owners, (uint8_t *)amacl->owners[i].id,
171                     sizeof(amacl->owners[i].id));
172                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Owners Array Value.");
173             }
174             cborEncoderResult |= cbor_encoder_close_container(&amaclMap, &owners);
175             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Owners Array.");
176         }
177         cborEncoderResult |= cbor_encoder_close_container(&amaclArray, &amaclMap);
178         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing AMACL Map.");
179
180         amacl = amacl->next;
181     }
182     cborEncoderResult |= cbor_encoder_close_container(&encoder, &amaclArray);
183     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Amacl Array.");
184
185     if (CborNoError == cborEncoderResult)
186     {
187         *cborPayload = outPayload;
188         *cborSize = encoder.ptr - outPayload;
189         ret = OC_STACK_OK;
190     }
191
192 exit:
193     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
194     {
195        // reallocate and try again!
196        OICFree(outPayload);
197        outPayload = NULL;
198        // Since the allocated initial memory failed, double the memory.
199        cborLen += encoder.ptr - encoder.end;
200        cborEncoderResult = CborNoError;
201        ret = AmaclToCBORPayload(amaclS, cborPayload, &cborLen);
202        if (OC_STACK_OK == ret)
203        {
204            *cborSize = cborLen;
205            ret = OC_STACK_OK;
206        }
207     }
208
209     if (CborNoError != cborEncoderResult)
210     {
211        OICFree(outPayload);
212        outPayload = NULL;
213        *cborSize = 0;
214        *cborPayload = NULL;
215        ret = OC_STACK_ERROR;
216     }
217
218     return ret;
219 }
220
221 OCStackResult CBORPayloadToAmacl(const uint8_t *cborPayload, size_t size,
222                                  OicSecAmacl_t **secAmacl)
223 {
224     if (NULL == cborPayload || NULL == secAmacl || NULL != *secAmacl)
225     {
226         return OC_STACK_INVALID_PARAM;
227     }
228
229     *secAmacl = NULL;
230
231     OCStackResult ret = OC_STACK_ERROR;
232
233     CborValue amaclCbor = { .parser = NULL };
234     CborParser parser = { .end = NULL };
235     CborError cborFindResult = CborNoError;
236     int cborLen = size;
237     if (0 == size)
238     {
239         cborLen = CBOR_SIZE;
240     }
241     cbor_parser_init(cborPayload, cborLen, 0, &parser, &amaclCbor);
242
243     OicSecAmacl_t *headAmacl = NULL;
244
245     CborValue amaclArray = { .parser = NULL };
246     cborFindResult = cbor_value_enter_container(&amaclCbor, &amaclArray);
247     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering Amacl Array.");
248
249     while (cbor_value_is_valid(&amaclArray))
250     {
251         CborValue amaclMap = { .parser = NULL };
252         cborFindResult = cbor_value_enter_container(&amaclArray, &amaclMap);
253         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering Amacl Map.");
254
255         OicSecAmacl_t *amacl = (OicSecAmacl_t *) OICCalloc(1, sizeof(*amacl));
256         VERIFY_NON_NULL(TAG, amacl, ERROR);
257
258         while (cbor_value_is_valid(&amaclMap))
259         {
260             char *name = NULL;
261             size_t len = 0;
262             cborFindResult = cbor_value_dup_text_string(&amaclMap, &name, &len, NULL);
263             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering Amacl Name.");
264             cborFindResult = cbor_value_advance(&amaclMap);
265             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering Amacl Advance.");
266
267             CborType type = cbor_value_get_type(&amaclMap);
268
269             // Resources -- Mandatory
270             if (0 == strcmp(OIC_JSON_RESOURCES_NAME, name))
271             {
272                 CborValue resources = { .parser = NULL  };
273                 cborFindResult = cbor_value_get_array_length(&amaclMap, &amacl->resourcesLen);
274                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Resource Name Array Len.");
275
276                 cborFindResult = cbor_value_enter_container(&amaclMap, &resources);
277                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering Amacl Array.");
278
279                 amacl->resources = (char **) OICCalloc(amacl->resourcesLen, sizeof(*amacl->resources));
280                 VERIFY_NON_NULL(TAG, amacl->resources, ERROR);
281                 int i = 0;
282                 while (cbor_value_is_text_string(&resources))
283                 {
284                     cborFindResult = cbor_value_dup_text_string(&resources, &amacl->resources[i++],
285                         &len, NULL);
286                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Resource Name Value.");
287                     cborFindResult = cbor_value_advance(&resources);
288                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Resource Name.");
289                 }
290             }
291
292             // Amss -- Mandatory
293             if (0 == strcmp(OIC_JSON_AMSS_NAME, name))
294             {
295                 CborValue amss = { .parser = NULL };
296                 cborFindResult = cbor_value_get_array_length(&amaclMap, &amacl->amssLen);
297                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering AMSS Name Array Len.");
298                 cborFindResult = cbor_value_enter_container(&amaclMap, &amss);
299                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering AMSS Name Container.");
300                 int i = 0;
301                 amacl->amss = (OicUuid_t *)OICCalloc(amacl->amssLen, sizeof(*amacl->amss));
302                 VERIFY_NON_NULL(TAG, amacl->amss, ERROR);
303                 while (cbor_value_is_valid(&amss))
304                 {
305                     uint8_t *amssId = NULL;
306                     cborFindResult = cbor_value_dup_byte_string(&amss, &amssId, &len, NULL);
307                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Adding AMSS Id.");
308                     cborFindResult = cbor_value_advance(&amss);
309                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing AMSS.");
310                     memcpy(amacl->amss[i++].id, amssId, len);
311                     OICFree(amssId);
312                 }
313             }
314
315             // Owners -- Mandatory
316             if (0 == strcmp(OIC_JSON_OWNERS_NAME, name))
317             {
318                 CborValue owners = { .parser = NULL };
319                 cborFindResult = cbor_value_get_array_length(&amaclMap, &amacl->ownersLen);
320                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Adding Owner Name Len.");
321                 cborFindResult = cbor_value_enter_container(&amaclMap, &owners);
322                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Container Owner Array.");
323                 int i = 0;
324                 amacl->owners = (OicUuid_t *)OICCalloc(amacl->ownersLen, sizeof(*amacl->owners));
325                 VERIFY_NON_NULL(TAG, amacl->owners, ERROR);
326                 while (cbor_value_is_valid(&owners))
327                 {
328                     uint8_t *owner = NULL;
329                     cborFindResult = cbor_value_dup_byte_string(&owners, &owner, &len, NULL);
330                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Adding Owners Array Value.");
331                     cborFindResult = cbor_value_advance(&owners);
332                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Owners Array");
333                     memcpy(amacl->owners[i++].id, owner, len);
334                     OICFree(owner);
335                 }
336             }
337             if (CborMapType != type && cbor_value_is_valid(&amaclMap))
338             {
339                 cborFindResult = cbor_value_advance(&amaclMap);
340                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Amacl Map.");
341             }
342             OICFree(name);
343         }
344
345         amacl->next = NULL;
346         if (NULL == headAmacl)
347         {
348             headAmacl = amacl;
349         }
350         else
351         {
352             OicSecAmacl_t *temp = headAmacl;
353             while (temp->next)
354             {
355                 temp = temp->next;
356             }
357             temp->next = amacl;
358         }
359         if (cbor_value_is_valid(&amaclArray))
360         {
361             cborFindResult = cbor_value_advance(&amaclArray);
362             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing AMACL Array.");
363         }
364     }
365     *secAmacl = headAmacl;
366     ret = OC_STACK_OK;
367
368 exit:
369     if (CborNoError != cborFindResult)
370     {
371         DeleteAmaclList(headAmacl);
372         headAmacl = NULL;
373         ret = OC_STACK_ERROR;
374     }
375     return ret;
376 }
377
378 static OCEntityHandlerResult HandleAmaclGetRequest (const OCEntityHandlerRequest * ehRequest)
379 {
380     // Convert Amacl data into JSON for transmission
381     size_t size = 0;
382     uint8_t *cborPayload = NULL;
383     OCStackResult res = AmaclToCBORPayload(gAmacl, &cborPayload, &size);
384
385     OCEntityHandlerResult ehRet = (res == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
386
387     // Send response payload to request originator
388     SendSRMCBORResponse(ehRequest, ehRet, cborPayload, size);
389
390     OICFree(cborPayload);
391
392     OIC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
393     return ehRet;
394 }
395
396 static OCEntityHandlerResult HandleAmaclPostRequest (const OCEntityHandlerRequest * ehRequest)
397 {
398     OCEntityHandlerResult ehRet = OC_EH_ERROR;
399
400     // Convert CBOR Amacl data into binary. This will also validate the Amacl data received.
401     uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData1;
402     size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
403     if (payload)
404     {
405         OicSecAmacl_t *newAmacl = NULL;
406         OCStackResult res = CBORPayloadToAmacl(payload, size, &newAmacl);
407         if (newAmacl && OC_STACK_OK == res)
408         {
409             // Append the new Amacl to existing Amacl
410             LL_APPEND(gAmacl, newAmacl);
411             size_t size = 0;
412             // Convert Amacl data into JSON for update to persistent storage.
413             uint8_t *cborPayload = NULL;
414             res = AmaclToCBORPayload(gAmacl, &cborPayload, &size);
415             if (cborPayload && (OC_STACK_OK == res) &&
416                 (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_AMACL_NAME, cborPayload, size)))
417             {
418                 ehRet = OC_EH_RESOURCE_CREATED;
419             }
420             OICFree(cborPayload);
421         }
422         OICFree(payload);
423     }
424
425     // Send payload to request originator
426     SendSRMCBORResponse(ehRequest, ehRet, NULL, 0);
427
428     OIC_LOG_V(DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
429     return ehRet;
430 }
431
432 /**
433  * This internal method is the entity handler for Amacl resources and
434  * will handle REST request (GET/PUT/POST/DEL) for them.
435  */
436 static OCEntityHandlerResult AmaclEntityHandler (OCEntityHandlerFlag flag,
437                                                  OCEntityHandlerRequest * ehRequest,
438                                                  void* callbackParameter)
439 {
440     (void) callbackParameter;
441     OCEntityHandlerResult ehRet = OC_EH_ERROR;
442
443     if (!ehRequest)
444     {
445         return ehRet;
446     }
447
448     if (flag & OC_REQUEST_FLAG)
449     {
450         OIC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
451         switch (ehRequest->method)
452         {
453             case OC_REST_GET:
454                 ehRet = HandleAmaclGetRequest(ehRequest);
455                 break;
456
457             case OC_REST_POST:
458                 ehRet = HandleAmaclPostRequest(ehRequest);
459                 break;
460
461             default:
462                 ehRet = OC_EH_ERROR;
463                 SendSRMCBORResponse(ehRequest, ehRet, NULL, 0);
464         }
465     }
466
467     return ehRet;
468 }
469
470 /**
471  * This internal method is used to create '/oic/sec/amacl' resource.
472  */
473 static OCStackResult CreateAmaclResource()
474 {
475     OCStackResult ret = OCCreateResource(&gAmaclHandle,
476                                          OIC_RSRC_TYPE_SEC_AMACL,
477                                          OIC_MI_DEF,
478                                          OIC_RSRC_AMACL_URI,
479                                          AmaclEntityHandler,
480                                          NULL,
481                                          OC_OBSERVABLE);
482
483     if (OC_STACK_OK != ret)
484     {
485         OIC_LOG (FATAL, TAG, "Unable to instantiate Amacl resource");
486         DeInitAmaclResource();
487     }
488     return ret;
489 }
490
491 OCStackResult InitAmaclResource()
492 {
493     OCStackResult ret = OC_STACK_ERROR;
494
495     uint8_t *data = NULL;
496     size_t size = 0;
497     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_AMACL_NAME, &data, &size);
498
499     // If database read failed
500     if (OC_STACK_OK != ret)
501     {
502         OIC_LOG(DEBUG, TAG, "ReadSVDataFromPS failed");
503     }
504     if (data)
505     {
506         // Read AMACL resource from PS
507         ret = CBORPayloadToAmacl(data, size, &gAmacl);
508         if (OC_STACK_OK != ret)
509         {
510             OIC_LOG(DEBUG, TAG, "ReadAMACLresourcefromPS failed");
511         }
512         OICFree(data);
513     }
514
515     // Instantiate 'oic/sec/amacl' resource
516     ret = CreateAmaclResource();
517
518     if (OC_STACK_OK != ret)
519     {
520         DeInitAmaclResource();
521     }
522     return ret;
523 }
524
525 void DeInitAmaclResource()
526 {
527     OCDeleteResource(gAmaclHandle);
528     gAmaclHandle = NULL;
529
530     DeleteAmaclList(gAmacl);
531     gAmacl = NULL;
532 }
533
534 OCStackResult AmaclGetAmsDeviceId(const char *resource, OicUuid_t *amsDeviceId)
535 {
536     OicSecAmacl_t *amacl = NULL;
537
538     VERIFY_NON_NULL(TAG, resource, ERROR);
539     VERIFY_NON_NULL(TAG, amsDeviceId, ERROR);
540
541     LL_FOREACH(gAmacl, amacl)
542     {
543         for(size_t i = 0; i < amacl->resourcesLen; i++)
544         {
545             if (0 == strncmp((amacl->resources[i]), resource, strlen(amacl->resources[i])))
546             {
547                 //Returning the ID of the first AMS service for the resource
548                 memcpy(amsDeviceId, &amacl->amss[0], sizeof(*amsDeviceId));
549                 return OC_STACK_OK;
550             }
551         }
552     }
553
554 exit:
555     return OC_STACK_ERROR;
556 }