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