Security code comments which are doxygen compliant
[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     CborError 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             for (size_t i = 0; i < amacl->resourcesLen; i++)
132             {
133                 cborEncoderResult = cbor_encode_text_string(&resources, amacl->resources[i],
134                     strlen(amacl->resources[i]));
135                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Resource Name Value in Array.");
136
137             }
138             cborEncoderResult = cbor_encoder_close_container(&amaclMap, &resources);
139             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Resource Name ");
140         }
141         // Amss -- Mandatory
142         {
143             CborEncoder amss = { {.ptr = NULL }, .end = 0 };
144             cborEncoderResult = cbor_encode_text_string(&amaclMap, OIC_JSON_AMSS_NAME,
145                 strlen(OIC_JSON_AMSS_NAME));
146             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMSS Name Tag.");
147             cborEncoderResult = cbor_encoder_create_array(&amaclMap, &amss, amacl->amssLen);
148             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMSS Name Array.");
149             for (size_t i = 0; i < amacl->amssLen; i++)
150             {
151                 cborEncoderResult = cbor_encode_byte_string(&amss, amacl->amss[i].id,
152                     sizeof(amacl->amss[i].id));
153                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding AMSS Name Value.");
154             }
155             cborEncoderResult = cbor_encoder_close_container(&amaclMap, &amss);
156             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing AMSS Array.");
157         }
158         // Owners -- Mandatory
159         {
160             cborEncoderResult = cbor_encode_text_string(&amaclMap, OIC_JSON_OWNERS_NAME,
161                 strlen(OIC_JSON_OWNERS_NAME));
162             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Owners Array Tag.");
163             CborEncoder owners = { {.ptr = NULL }, .end = 0};
164             cborEncoderResult = cbor_encoder_create_array(&amaclMap, &owners, amacl->ownersLen);
165             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Owners Array.");
166             for (size_t i = 0; i < amacl->ownersLen; i++)
167             {
168                 cborEncoderResult = cbor_encode_byte_string(&owners, (uint8_t *)amacl->owners[i].id,
169                     sizeof(amacl->owners[i].id));
170                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Owners Array Value.");
171             }
172             cborEncoderResult = cbor_encoder_close_container(&amaclMap, &owners);
173             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Owners Array.");
174         }
175         cborEncoderResult = cbor_encoder_close_container(&amaclArray, &amaclMap);
176         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing AMACL Map.");
177
178         amacl = amacl->next;
179     }
180     cborEncoderResult = cbor_encoder_close_container(&encoder, &amaclArray);
181     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Amacl Array.");
182
183     if (CborNoError == cborEncoderResult)
184     {
185         *cborPayload = outPayload;
186         *cborSize = encoder.ptr - outPayload;
187         ret = OC_STACK_OK;
188     }
189
190 exit:
191     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
192     {
193        // reallocate and try again!
194        OICFree(outPayload);
195        outPayload = NULL;
196        // Since the allocated initial memory failed, double the memory.
197        cborLen += encoder.ptr - encoder.end;
198        cborEncoderResult = CborNoError;
199        ret = AmaclToCBORPayload(amaclS, cborPayload, &cborLen);
200        if (OC_STACK_OK == ret)
201        {
202            *cborSize = cborLen;
203            ret = OC_STACK_OK;
204        }
205     }
206
207     if (CborNoError != cborEncoderResult)
208     {
209        OICFree(outPayload);
210        outPayload = NULL;
211        *cborSize = 0;
212        *cborPayload = NULL;
213        ret = OC_STACK_ERROR;
214     }
215
216     return ret;
217 }
218
219 OCStackResult CBORPayloadToAmacl(const uint8_t *cborPayload, size_t size,
220                                  OicSecAmacl_t **secAmacl)
221 {
222     if (NULL == cborPayload || NULL == secAmacl || NULL != *secAmacl)
223     {
224         return OC_STACK_INVALID_PARAM;
225     }
226
227     *secAmacl = NULL;
228
229     OCStackResult ret = OC_STACK_ERROR;
230
231     CborValue amaclCbor = { .parser = NULL };
232     CborParser parser = { .end = NULL };
233     CborError cborFindResult = CborNoError;
234     int cborLen = size;
235     if (0 == size)
236     {
237         cborLen = CBOR_SIZE;
238     }
239     cbor_parser_init(cborPayload, cborLen, 0, &parser, &amaclCbor);
240
241     OicSecAmacl_t *headAmacl = NULL;
242
243     CborValue amaclArray = { .parser = NULL };
244     cborFindResult = cbor_value_enter_container(&amaclCbor, &amaclArray);
245     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
246
247     while (cbor_value_is_valid(&amaclArray))
248     {
249         CborValue amaclMap = { .parser = NULL };
250         cborFindResult = cbor_value_enter_container(&amaclArray, &amaclMap);
251         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
252
253         OicSecAmacl_t *amacl = (OicSecAmacl_t *) OICCalloc(1, sizeof(*amacl));
254         VERIFY_NON_NULL(TAG, amacl, ERROR);
255
256         while (cbor_value_is_valid(&amaclMap))
257         {
258             char *name = NULL;
259             size_t len = 0;
260             cborFindResult = cbor_value_dup_text_string(&amaclMap, &name, &len, NULL);
261             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
262             cborFindResult = cbor_value_advance(&amaclMap);
263             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
264
265             CborType type = cbor_value_get_type(&amaclMap);
266
267             // Resources -- Mandatory
268             if (0 == strcmp(OIC_JSON_RESOURCES_NAME, name))
269             {
270                 CborValue resources = { .parser = NULL  };
271                 cborFindResult = cbor_value_get_array_length(&amaclMap, &amacl->resourcesLen);
272                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
273
274                 cborFindResult = cbor_value_enter_container(&amaclMap, &resources);
275                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
276
277                 amacl->resources = (char **) OICMalloc(amacl->resourcesLen * sizeof(*amacl->resources));
278                 VERIFY_NON_NULL(TAG, amacl->resources, ERROR);
279                 int i = 0;
280                 while (cbor_value_is_text_string(&resources))
281                 {
282                     cborFindResult = cbor_value_dup_text_string(&resources, &amacl->resources[i++],
283                         &len, NULL);
284                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
285                     cborFindResult = cbor_value_advance(&resources);
286                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
287                 }
288             }
289
290             // Amss -- Mandatory
291             if (0 == strcmp(OIC_JSON_AMSS_NAME, name))
292             {
293                 CborValue amss = { .parser = NULL };
294                 cborFindResult = cbor_value_get_array_length(&amaclMap, &amacl->amssLen);
295                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
296                 cborFindResult = cbor_value_enter_container(&amaclMap, &amss);
297                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
298                 int i = 0;
299                 amacl->amss = (OicUuid_t *)OICCalloc(amacl->amssLen, sizeof(*amacl->amss));
300                 VERIFY_NON_NULL(TAG, amacl->amss, ERROR);
301                 while (cbor_value_is_valid(&amss))
302                 {
303                     uint8_t *amssId = NULL;
304                     cborFindResult = cbor_value_dup_byte_string(&amss, &amssId, &len, NULL);
305                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
306                     cborFindResult = cbor_value_advance(&amss);
307                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
308                     memcpy(amacl->amss[i].id, amssId, len);
309                     OICFree(amssId);
310                 }
311             }
312
313             // Owners -- Mandatory
314             if (0 == strcmp(OIC_JSON_OWNERS_NAME, name))
315             {
316                 CborValue owners = { .parser = NULL };
317                 cborFindResult = cbor_value_get_array_length(&amaclMap, &amacl->ownersLen);
318                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
319                 cborFindResult = cbor_value_enter_container(&amaclMap, &owners);
320                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
321                 int i = 0;
322                 amacl->owners = (OicUuid_t *)OICCalloc(amacl->ownersLen, sizeof(*amacl->owners));
323                 VERIFY_NON_NULL(TAG, amacl->owners, ERROR);
324                 while (cbor_value_is_valid(&owners))
325                 {
326                     uint8_t *owner = NULL;
327                     cborFindResult = cbor_value_dup_byte_string(&owners, &owner, &len, NULL);
328                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
329                     cborFindResult = cbor_value_advance(&owners);
330                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
331                     memcpy(amacl->owners[i].id, owner, len);
332                     OICFree(owner);
333                 }
334             }
335             if (CborMapType != type && cbor_value_is_valid(&amaclMap))
336             {
337                 cborFindResult = cbor_value_advance(&amaclMap);
338                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
339             }
340             OICFree(name);
341         }
342
343         amacl->next = NULL;
344         if (NULL == headAmacl)
345         {
346             headAmacl = amacl;
347         }
348         else
349         {
350             OicSecAmacl_t *temp = headAmacl;
351             while (temp->next)
352             {
353                 temp = temp->next;
354             }
355             temp->next = amacl;
356         }
357         if (cbor_value_is_valid(&amaclArray))
358         {
359             cborFindResult = cbor_value_advance(&amaclArray);
360             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
361         }
362     }
363     *secAmacl = headAmacl;
364     ret = OC_STACK_OK;
365 exit:
366     if (CborNoError != cborFindResult)
367     {
368         DeleteAmaclList(headAmacl);
369         headAmacl = NULL;
370         ret = OC_STACK_ERROR;
371     }
372     return ret;
373 }
374
375 static OCEntityHandlerResult HandleAmaclGetRequest (const OCEntityHandlerRequest * ehRequest)
376 {
377     // Convert Amacl data into JSON for transmission
378     size_t size = 0;
379     uint8_t *cborPayload = NULL;
380     OCStackResult res = AmaclToCBORPayload(gAmacl, &cborPayload, &size);
381
382     OCEntityHandlerResult ehRet = (res == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
383
384     // Send response payload to request originator
385     SendSRMCBORResponse(ehRequest, ehRet, cborPayload);
386
387     OICFree(cborPayload);
388
389     OIC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
390     return ehRet;
391 }
392
393 static OCEntityHandlerResult HandleAmaclPostRequest (const OCEntityHandlerRequest * ehRequest)
394 {
395     OCEntityHandlerResult ehRet = OC_EH_ERROR;
396
397     // Convert CBOR Amacl data into binary. This will also validate the Amacl data received.
398     uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData1;;
399     if (payload)
400     {
401         OicSecAmacl_t *newAmacl = NULL;
402         OCStackResult res = CBORPayloadToAmacl(payload, CBOR_SIZE, &newAmacl);
403         if (newAmacl && OC_STACK_OK == res)
404         {
405             // Append the new Amacl to existing Amacl
406             LL_APPEND(gAmacl, newAmacl);
407             size_t size = 0;
408             // Convert Amacl data into JSON for update to persistent storage.
409             uint8_t *cborPayload = NULL;
410             res = AmaclToCBORPayload(gAmacl, &cborPayload, &size);
411             if (cborPayload && (OC_STACK_OK == res) &&
412                 (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_AMACL_NAME, cborPayload, size)))
413             {
414                 ehRet = OC_EH_RESOURCE_CREATED;
415             }
416             OICFree(cborPayload);
417         }
418         OICFree(payload);
419     }
420
421     // Send payload to request originator
422     SendSRMCBORResponse(ehRequest, ehRet, NULL);
423
424     OIC_LOG_V(DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
425     return ehRet;
426 }
427
428 /**
429  * This internal method is the entity handler for Amacl resources and
430  * will handle REST request (GET/PUT/POST/DEL) for them.
431  */
432 static OCEntityHandlerResult AmaclEntityHandler (OCEntityHandlerFlag flag,
433                                                  OCEntityHandlerRequest * ehRequest,
434                                                  void* callbackParameter)
435 {
436     (void) callbackParameter;
437     OCEntityHandlerResult ehRet = OC_EH_ERROR;
438
439     if (!ehRequest)
440     {
441         return ehRet;
442     }
443
444     if (flag & OC_REQUEST_FLAG)
445     {
446         OIC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
447         switch (ehRequest->method)
448         {
449             case OC_REST_GET:
450                 ehRet = HandleAmaclGetRequest(ehRequest);
451                 break;
452
453             case OC_REST_POST:
454                 ehRet = HandleAmaclPostRequest(ehRequest);
455                 break;
456
457             default:
458                 ehRet = OC_EH_ERROR;
459                 SendSRMResponse(ehRequest, ehRet, NULL);
460         }
461     }
462
463     return ehRet;
464 }
465
466 /**
467  * This internal method is used to create '/oic/sec/amacl' resource.
468  */
469 static OCStackResult CreateAmaclResource()
470 {
471     OCStackResult ret = OCCreateResource(&gAmaclHandle,
472                                          OIC_RSRC_TYPE_SEC_AMACL,
473                                          OIC_MI_DEF,
474                                          OIC_RSRC_AMACL_URI,
475                                          AmaclEntityHandler,
476                                          NULL,
477                                          OC_OBSERVABLE);
478
479     if (OC_STACK_OK != ret)
480     {
481         OIC_LOG (FATAL, TAG, "Unable to instantiate Amacl resource");
482         DeInitAmaclResource();
483     }
484     return ret;
485 }
486
487 OCStackResult InitAmaclResource()
488 {
489     OCStackResult ret = OC_STACK_ERROR;
490
491     uint8_t *data = NULL;
492     size_t size = 0;
493     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_AMACL_NAME, &data, &size);
494
495     // If database read failed
496     if (OC_STACK_OK != ret)
497     {
498         OIC_LOG(DEBUG, TAG, "ReadSVDataFromPS failed");
499     }
500     if (data)
501     {
502         // Read AMACL resource from PS
503         ret = CBORPayloadToAmacl(data, size, &gAmacl);
504         OICFree(data);
505     }
506
507     // Instantiate 'oic/sec/amacl' resource
508     ret = CreateAmaclResource();
509
510     if (OC_STACK_OK != ret)
511     {
512         DeInitAmaclResource();
513     }
514     return ret;
515 }
516
517 void DeInitAmaclResource()
518 {
519     OCDeleteResource(gAmaclHandle);
520     gAmaclHandle = NULL;
521
522     DeleteAmaclList(gAmacl);
523     gAmacl = NULL;
524 }
525
526 OCStackResult AmaclGetAmsDeviceId(const char *resource, OicUuid_t *amsDeviceId)
527 {
528     OicSecAmacl_t *amacl = NULL;
529
530     VERIFY_NON_NULL(TAG, resource, ERROR);
531     VERIFY_NON_NULL(TAG, amsDeviceId, ERROR);
532
533     LL_FOREACH(gAmacl, amacl)
534     {
535         for(size_t i = 0; i < amacl->resourcesLen; i++)
536         {
537             if (0 == strncmp((amacl->resources[i]), resource, strlen(amacl->resources[i])))
538             {
539                 //Returning the ID of the first AMS service for the resource
540                 memcpy(amsDeviceId, &amacl->amss[0], sizeof(*amsDeviceId));
541                 return OC_STACK_OK;
542             }
543         }
544     }
545
546 exit:
547     return OC_STACK_ERROR;
548 }