Update secure resource related modules(SRM,OTM,SRP,CKM,unit tests,samples)
[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 "ocstack.h"
25 #include "logger.h"
26 #include "oic_malloc.h"
27 #include "oic_string.h"
28 #include "cJSON.h"
29 #include "base64.h"
30 #include "resourcemanager.h"
31 #include "psinterface.h"
32 #include "utlist.h"
33 #include "srmresourcestrings.h"
34 #include "amaclresource.h"
35 #include "srmutility.h"
36 #include <stdlib.h>
37 #include <string.h>
38
39 #define TAG  "SRM-AMACL"
40
41 OicSecAmacl_t *gAmacl = NULL;
42 static OCResourceHandle gAmaclHandle = NULL;
43
44 void DeleteAmaclList(OicSecAmacl_t* amacl)
45 {
46     if (amacl)
47     {
48         OicSecAmacl_t *amaclTmp1 = NULL, *amaclTmp2 = NULL;
49         LL_FOREACH_SAFE(amacl, amaclTmp1, amaclTmp2)
50         {
51             unsigned int i = 0;
52
53             LL_DELETE(amacl, amaclTmp1);
54
55             // Clean Resources
56             for (i = 0; i < amaclTmp1->resourcesLen; i++)
57             {
58                 OICFree(amaclTmp1->resources[i]);
59             }
60             OICFree(amaclTmp1->resources);
61
62             // Clean Amss
63             OICFree(amaclTmp1->amss);
64
65             // Clean Owners
66             OICFree(amaclTmp1->owners);
67
68             // Clean Amacl node itself
69             OICFree(amaclTmp1);
70         }
71     }
72 }
73
74 /*
75  * This internal method converts AMACL data into JSON format.
76  *
77  * Note: Caller needs to invoke 'free' when finished using the return string.
78  */
79 char * BinToAmaclJSON(const OicSecAmacl_t * amacl, const bool isIncResName)
80 {
81     cJSON *jsonRoot = NULL;
82     char *jsonStr = NULL;
83
84     if (amacl)
85     {
86         cJSON *jsonAmaclArray = NULL;
87         if(isIncResName)
88         {
89             jsonRoot = cJSON_CreateObject();
90             VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
91             cJSON_AddItemToObject(jsonRoot, OIC_JSON_AMACL_NAME,
92                                   jsonAmaclArray = cJSON_CreateArray());
93         }
94         else
95         {
96             jsonAmaclArray = cJSON_CreateArray();
97             jsonRoot = jsonAmaclArray;
98         }
99         VERIFY_NON_NULL(TAG, jsonAmaclArray, ERROR);
100
101         while(amacl)
102         {
103             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
104             uint32_t outLen = 0;
105             B64Result b64Ret = B64_OK;
106
107             cJSON *jsonAmacl = cJSON_CreateObject();
108
109             // Resources -- Mandatory
110             cJSON *jsonRsrcArray = NULL;
111             cJSON_AddItemToObject(jsonAmacl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray =
112                     cJSON_CreateArray());
113             VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR);
114             for (unsigned int i = 0; i < amacl->resourcesLen; i++)
115             {
116                 cJSON_AddItemToArray(jsonRsrcArray, cJSON_CreateString(amacl->resources[i]));
117             }
118
119             // Amss -- Mandatory
120             cJSON *jsonAmsArray = NULL;
121             cJSON_AddItemToObject(jsonAmacl, OIC_JSON_AMSS_NAME, jsonAmsArray =
122                     cJSON_CreateArray());
123             VERIFY_NON_NULL(TAG, jsonAmsArray, ERROR);
124             for (unsigned int i = 0; i < amacl->amssLen; i++)
125             {
126                 outLen = 0;
127
128                 b64Ret = b64Encode(amacl->amss[i].id, sizeof(((OicUuid_t*) 0)->id), base64Buff,
129                         sizeof(base64Buff), &outLen);
130                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
131
132                 cJSON_AddItemToArray(jsonAmsArray, cJSON_CreateString(base64Buff));
133             }
134
135             // Owners -- Mandatory
136             cJSON *jsonOwnrArray = NULL;
137             cJSON_AddItemToObject(jsonAmacl, OIC_JSON_OWNERS_NAME, jsonOwnrArray =
138                     cJSON_CreateArray());
139             VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
140             for (unsigned int i = 0; i < amacl->ownersLen; i++)
141             {
142                 outLen = 0;
143
144                 b64Ret = b64Encode(amacl->owners[i].id, sizeof(((OicUuid_t*) 0)->id), base64Buff,
145                         sizeof(base64Buff), &outLen);
146                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
147
148                 cJSON_AddItemToArray(jsonOwnrArray, cJSON_CreateString(base64Buff));
149             }
150
151             // Attach current amacl node to Amacl Array
152             cJSON_AddItemToArray(jsonAmaclArray, jsonAmacl);
153             amacl = amacl->next;
154         }
155
156         jsonStr = cJSON_PrintUnformatted(jsonRoot);
157     }
158
159 exit:
160     if (jsonRoot)
161     {
162         cJSON_Delete(jsonRoot);
163     }
164     return jsonStr;
165 }
166
167
168
169
170 /*
171  * This internal method converts JSON AMACL into binary AMACL.
172  */
173 OicSecAmacl_t * JSONToAmaclBin(const char * jsonStr, const bool isIncResName)
174 {
175     OCStackResult ret = OC_STACK_ERROR;
176     OicSecAmacl_t * headAmacl = NULL;
177     OicSecAmacl_t * prevAmacl = NULL;
178     cJSON *jsonRoot = NULL;
179     cJSON *jsonAmaclArray = NULL;
180
181     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
182
183     jsonRoot = cJSON_Parse(jsonStr);
184     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
185
186     if(isIncResName)
187     {
188         jsonAmaclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_AMACL_NAME);
189     }
190     else
191     {
192         jsonAmaclArray = jsonRoot;
193     }
194     VERIFY_NON_NULL(TAG, jsonAmaclArray, INFO);
195
196     if (cJSON_Array == jsonAmaclArray->type)
197     {
198         int numAmacl = cJSON_GetArraySize(jsonAmaclArray);
199         int idx = 0;
200
201         VERIFY_SUCCESS(TAG, numAmacl > 0, INFO);
202         do
203         {
204             cJSON *jsonAmacl = cJSON_GetArrayItem(jsonAmaclArray, idx);
205             VERIFY_NON_NULL(TAG, jsonAmacl, ERROR);
206
207             OicSecAmacl_t *amacl = (OicSecAmacl_t*)OICCalloc(1, sizeof(OicSecAmacl_t));
208             VERIFY_NON_NULL(TAG, amacl, ERROR);
209
210             headAmacl = (headAmacl) ? headAmacl : amacl;
211             if (prevAmacl)
212             {
213                 prevAmacl->next = amacl;
214             }
215
216             size_t jsonObjLen = 0;
217             cJSON *jsonObj = NULL;
218
219             // Resources -- Mandatory
220             jsonObj = cJSON_GetObjectItem(jsonAmacl, OIC_JSON_RESOURCES_NAME);
221             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
222             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
223
224             amacl->resourcesLen = cJSON_GetArraySize(jsonObj);
225             VERIFY_SUCCESS(TAG, amacl->resourcesLen > 0, ERROR);
226             amacl->resources = (char**)OICCalloc(amacl->resourcesLen, sizeof(char*));
227             VERIFY_NON_NULL(TAG, (amacl->resources), ERROR);
228
229             size_t idxx = 0;
230             do
231             {
232                 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
233                 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
234
235                 jsonObjLen = strlen(jsonRsrc->valuestring) + 1;
236                 amacl->resources[idxx] = (char*)OICMalloc(jsonObjLen);
237                 VERIFY_NON_NULL(TAG, (amacl->resources[idxx]), ERROR);
238                 OICStrcpy(amacl->resources[idxx], jsonObjLen, jsonRsrc->valuestring);
239             } while ( ++idxx < amacl->resourcesLen);
240
241             // Amss -- Mandatory
242             VERIFY_SUCCESS( TAG, OC_STACK_OK == AddUuidArray(jsonAmacl, OIC_JSON_AMSS_NAME,
243                                &(amacl->amssLen), &(amacl->amss)), ERROR);
244
245             // Owners -- Mandatory
246             VERIFY_SUCCESS( TAG, OC_STACK_OK == AddUuidArray(jsonAmacl, OIC_JSON_OWNERS_NAME,
247                                &(amacl->ownersLen), &(amacl->owners)), ERROR);
248
249             prevAmacl = amacl;
250         } while( ++idx < numAmacl);
251     }
252
253     ret = OC_STACK_OK;
254
255 exit:
256     cJSON_Delete(jsonRoot);
257     if (OC_STACK_OK != ret)
258     {
259         DeleteAmaclList(headAmacl);
260         headAmacl = NULL;
261     }
262     return headAmacl;
263 }
264
265 static OCEntityHandlerResult HandleAmaclGetRequest (const OCEntityHandlerRequest * ehRequest)
266 {
267     // Convert Amacl data into JSON for transmission
268     char* jsonStr = BinToAmaclJSON(gAmacl, false);
269
270     OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
271
272     // Send response payload to request originator
273     SendSRMResponse(ehRequest, ehRet, jsonStr);
274
275     OICFree(jsonStr);
276
277     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
278     return ehRet;
279 }
280
281 static OCEntityHandlerResult HandleAmaclPostRequest (const OCEntityHandlerRequest * ehRequest)
282 {
283     OCEntityHandlerResult ehRet = OC_EH_ERROR;
284
285     // Convert JSON Amacl data into binary. This will also validate the Amacl data received.
286     OicSecAmacl_t* newAmacl = JSONToAmaclBin(((OCSecurityPayload*)ehRequest->payload)->securityData, false);
287
288     if (newAmacl)
289     {
290         // Append the new Amacl to existing Amacl
291         LL_APPEND(gAmacl, newAmacl);
292
293         // Convert Amacl data into JSON for update to persistent storage
294         char *jsonStr = BinToAmaclJSON(gAmacl, true);
295         if (jsonStr)
296         {
297             cJSON *jsonAmacl = cJSON_Parse(jsonStr);
298             OICFree(jsonStr);
299
300             if ((jsonAmacl) &&
301                 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_AMACL_NAME, jsonAmacl)))
302             {
303                 ehRet = OC_EH_RESOURCE_CREATED;
304             }
305             cJSON_Delete(jsonAmacl);
306         }
307     }
308
309     // Send payload to request originator
310     SendSRMResponse(ehRequest, ehRet, NULL);
311
312     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
313     return ehRet;
314 }
315
316 /*
317  * This internal method is the entity handler for Amacl resources and
318  * will handle REST request (GET/PUT/POST/DEL) for them.
319  */
320 OCEntityHandlerResult AmaclEntityHandler (OCEntityHandlerFlag flag,
321                                           OCEntityHandlerRequest * ehRequest,
322                                           void* callbackParameter)
323 {
324     (void) callbackParameter;
325     OCEntityHandlerResult ehRet = OC_EH_ERROR;
326
327     if (!ehRequest)
328     {
329         return ehRet;
330     }
331
332     if (flag & OC_REQUEST_FLAG)
333     {
334         OC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
335         switch (ehRequest->method)
336         {
337             case OC_REST_GET:
338                 ehRet = HandleAmaclGetRequest(ehRequest);
339                 break;
340
341             case OC_REST_POST:
342                 ehRet = HandleAmaclPostRequest(ehRequest);
343                 break;
344
345             default:
346                 ehRet = OC_EH_ERROR;
347                 SendSRMResponse(ehRequest, ehRet, NULL);
348         }
349     }
350
351     return ehRet;
352 }
353
354 /*
355  * This internal method is used to create '/oic/sec/amacl' resource.
356  */
357 OCStackResult CreateAmaclResource()
358 {
359     OCStackResult ret;
360
361     ret = OCCreateResource(&gAmaclHandle,
362                            OIC_RSRC_TYPE_SEC_AMACL,
363                            OIC_MI_DEF,
364                            OIC_RSRC_AMACL_URI,
365                            AmaclEntityHandler,
366                            NULL,
367                            OC_OBSERVABLE);
368
369     if (OC_STACK_OK != ret)
370     {
371         OC_LOG (FATAL, TAG, "Unable to instantiate Amacl resource");
372         DeInitAmaclResource();
373     }
374     return ret;
375 }
376
377 /**
378  * Initialize Amacl resource by loading data from persistent storage.
379  *
380  * @retval  OC_STACK_OK for Success, otherwise some error value
381  */
382 OCStackResult InitAmaclResource()
383 {
384     OCStackResult ret = OC_STACK_ERROR;
385
386     // Read Amacl resource from PS
387     char* jsonSVRDatabase = GetSVRDatabase();
388
389     if (jsonSVRDatabase)
390     {
391         // Convert JSON Amacl into binary format
392         gAmacl = JSONToAmaclBin(jsonSVRDatabase, true);
393         OICFree(jsonSVRDatabase);
394     }
395
396     // Instantiate 'oic/sec/amacl' resource
397     ret = CreateAmaclResource();
398
399     if (OC_STACK_OK != ret)
400     {
401         DeInitAmaclResource();
402     }
403     return ret;
404 }
405
406 /**
407  * Perform cleanup for Amacl resources.
408  *
409  * @retval  none
410  */
411 void DeInitAmaclResource()
412 {
413     OCDeleteResource(gAmaclHandle);
414     gAmaclHandle = NULL;
415
416     DeleteAmaclList(gAmacl);
417     gAmacl = NULL;
418 }
419
420
421 OCStackResult AmaclGetAmsDeviceId(const char *resource, OicUuid_t *amsDeviceId)
422 {
423     OicSecAmacl_t *amacl = NULL;
424
425     VERIFY_NON_NULL(TAG, resource, ERROR);
426     VERIFY_NON_NULL(TAG, amsDeviceId, ERROR);
427
428     LL_FOREACH(gAmacl, amacl)
429     {
430         for(size_t i = 0; i < amacl->resourcesLen; i++)
431         {
432             if (strncmp((amacl->resources[i]), resource, strlen(amacl->resources[i])) == 0)
433             {
434                 //Returning the ID of the first AMS service for the resource
435                 memcpy(amsDeviceId, &amacl->amss[0], sizeof(*amsDeviceId));
436                 return OC_STACK_OK;
437             }
438         }
439     }
440
441 exit:
442     return OC_STACK_ERROR;
443 }