Imported Upstream version 1.0.1
[platform/upstream/iotivity.git] / resource / csdk / security / src / credresource.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 #define __STDC_LIMIT_MACROS
22 #include "ocstack.h"
23 #include "logger.h"
24 #include "oic_malloc.h"
25 #include "cJSON.h"
26 #include "resourcemanager.h"
27 #include "psinterface.h"
28 #include "utlist.h"
29 #include "srmresourcestrings.h"
30 #include "credresource.h"
31 #include "ocrandom.h"
32 #include "doxmresource.h"
33 #include "base64.h"
34 #include "srmutility.h"
35 #include "cainterface.h"
36 #include "pbkdf2.h"
37 #include <stdlib.h>
38 #include "iotvticalendar.h"
39 #ifdef WITH_ARDUINO
40 #include <string.h>
41 #else
42 #include <strings.h>
43 #endif
44 #include <stdint.h>
45
46 #define TAG  "SRM-CREDL"
47
48
49 static OicSecCred_t        *gCred = NULL;
50 static OCResourceHandle    gCredHandle = NULL;
51
52 /**
53  * This function frees OicSecCred_t object's fields and object itself.
54  */
55 static void FreeCred(OicSecCred_t *cred)
56 {
57     if(NULL == cred)
58     {
59         OC_LOG (ERROR, TAG, "Invalid Parameter");
60         return;
61     }
62     //Note: Need further clarification on roleID data type
63 #if 0
64     //Clean roleIds
65     OICFree(cred->roleIds);
66 #endif
67
68     //Clean PublicData
69     OICFree(cred->publicData.data);
70
71     //Clean PrivateData
72     OICFree(cred->privateData.data);
73
74     //Clean Period
75     OICFree(cred->period);
76
77     //Clean Owners
78     OICFree(cred->owners);
79
80     //Clean Cred node itself
81     OICFree(cred);
82 }
83
84 void DeleteCredList(OicSecCred_t* cred)
85 {
86     if (cred)
87     {
88         OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
89         LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
90         {
91             LL_DELETE(cred, credTmp1);
92             FreeCred(credTmp1);
93         }
94     }
95 }
96
97 /**
98  * This function converts credential data into JSON format.
99  * Caller needs to invoke 'free' when done using
100  * returned string.
101  * @param cred  pointer to instance of OicSecCred_t structure.
102  *
103  * @retval
104  *      pointer to JSON credential representation - if credential for subjectId found
105  *      NULL                                      - if credential for subjectId not found
106  */
107 char * BinToCredJSON(const OicSecCred_t * cred)
108 {
109     cJSON *jsonRoot = NULL;
110     char *jsonStr = NULL;
111
112     if (cred)
113     {
114         char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
115         uint32_t outLen = 0;
116         B64Result b64Ret = B64_OK;
117
118         jsonRoot = cJSON_CreateObject();
119         VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
120
121         cJSON *jsonCredArray = NULL;
122         cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
123                 jsonCredArray = cJSON_CreateArray());
124         VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
125
126         while(cred)
127         {
128             cJSON *jsonCred = cJSON_CreateObject();
129             VERIFY_NON_NULL(TAG, jsonCred, ERROR);
130
131             //CredID -- Mandatory
132             cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
133
134             //Subject -- Mandatory
135             outLen = 0;
136             memset(base64Buff, 0, sizeof(base64Buff));
137             b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
138                    sizeof(base64Buff), &outLen);
139             VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
140             cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
141
142             //Note: Need further clarification on roleID data type
143 #if 0
144             //RoleId -- Not Mandatory
145             if(cred->roleIdsLen > 0)
146             {
147                 cJSON *jsonRoleIdsArray = NULL;
148                 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
149                                          jsonRoleIdsArray = cJSON_CreateArray());
150                 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
151                 for (size_t i = 0; i < cred->roleIdsLen; i++)
152                 {
153                     cJSON_AddItemToArray (jsonRoleIdsArray,
154                             cJSON_CreateString((char *)cred->roleIds[i].id));
155                 }
156             }
157 #endif
158
159             //CredType -- Mandatory
160             cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
161
162 #ifdef __WITH_X509__
163             //PublicData -- Not Mandatory
164             if(cred->publicData.data)
165             {
166                 if (SIGNED_ASYMMETRIC_KEY == cred->credType)
167                 {
168                     cJSON_AddItemToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME,
169                                           cJSON_Parse(cred->publicData.data));
170                 }
171                 else
172                 {
173                 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
174                 }
175             }
176 #endif /*__WITH_X509__*/
177             //PrivateData -- Not Mandatory
178             if(cred->privateData.data)
179             {
180 #ifdef __WITH_X509__
181                 if (SIGNED_ASYMMETRIC_KEY == cred->credType)
182                 {
183                     cJSON_AddItemToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME,
184                                           cJSON_Parse(cred->privateData.data));
185                 }
186                 else
187                 {
188                     cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
189                 }
190 #else
191                 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
192 #endif
193             }
194
195             //Period -- Not Mandatory
196             if(cred->period)
197             {
198                 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
199                                         cred->period);
200             }
201
202             //Owners -- Mandatory
203             cJSON *jsonOwnrArray = NULL;
204             cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
205                                              jsonOwnrArray = cJSON_CreateArray());
206             VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
207             for (size_t i = 0; i < cred->ownersLen; i++)
208             {
209                 outLen = 0;
210                 memset(base64Buff, 0, sizeof(base64Buff));
211                 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
212                         base64Buff, sizeof(base64Buff), &outLen);
213                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
214                 cJSON_AddItemToArray (jsonOwnrArray,
215                                        cJSON_CreateString((char *)(base64Buff)));
216             }
217
218             /* Attach current cred node to cred Array */
219             cJSON_AddItemToArray(jsonCredArray, jsonCred);
220             cred = cred->next;
221         }
222
223         jsonStr = cJSON_PrintUnformatted(jsonRoot);
224     }
225
226 exit:
227     if (jsonRoot)
228     {
229         cJSON_Delete(jsonRoot);
230     }
231     return jsonStr;
232 }
233
234 /*
235  * This internal method converts JSON cred into binary cred.
236  */
237 OicSecCred_t * JSONToCredBin(const char * jsonStr)
238 {
239     OCStackResult ret = OC_STACK_ERROR;
240     OicSecCred_t * headCred = NULL;
241     OicSecCred_t * prevCred = NULL;
242     cJSON *jsonCredArray = NULL;
243
244     cJSON *jsonRoot = cJSON_Parse(jsonStr);
245     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
246
247     jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
248     VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
249     if (cJSON_Array == jsonCredArray->type)
250     {
251         int numCred = cJSON_GetArraySize(jsonCredArray);
252         int idx = 0;
253
254         unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
255         uint32_t outLen = 0;
256         B64Result b64Ret = B64_OK;
257
258         VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
259         do
260         {
261             cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
262             VERIFY_NON_NULL(TAG, jsonCred, ERROR);
263
264             OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
265             VERIFY_NON_NULL(TAG, cred, ERROR);
266
267             headCred = (headCred) ? headCred : cred;
268             if (prevCred)
269             {
270                 prevCred->next = cred;
271             }
272             size_t jsonObjLen = 0;
273             cJSON *jsonObj = NULL;
274
275             //CredId -- Mandatory
276             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
277             if(jsonObj)
278             {
279                 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
280                 cred->credId = jsonObj->valueint;
281             }
282
283             //subject -- Mandatory
284             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
285             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
286             VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
287             outLen = 0;
288             memset(base64Buff, 0, sizeof(base64Buff));
289             b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
290                     base64Buff, sizeof(base64Buff), &outLen);
291             VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
292                            ERROR);
293             memcpy(cred->subject.id, base64Buff, outLen);
294
295             //CredType -- Mandatory
296             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
297             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
298             VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
299             cred->credType = (OicSecCredType_t)jsonObj->valueint;
300
301             //PrivateData is mandatory for some of the credential types listed below.
302             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
303             if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
304                 (cred->credType & SYMMETRIC_GROUP_KEY) ||
305                 (cred->credType & PIN_PASSWORD))
306             {
307                 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
308                 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
309             }
310 #ifdef __WITH_X509__
311             else if (cred->credType & SIGNED_ASYMMETRIC_KEY)
312             {
313                 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
314                 VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
315             }
316 #endif //  __WITH_X509__
317             if (NULL != jsonObj)
318             {
319                 if (cJSON_String == jsonObj->type)
320                 {
321                     jsonObjLen = strlen(jsonObj->valuestring) + 1;
322                     cred->privateData.data = (char *)OICMalloc(jsonObjLen);
323                     VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
324                     strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
325                 }
326 #ifdef __WITH_X509__
327                 else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
328                 {
329                     cred->privateData.data = cJSON_PrintUnformatted(jsonObj);
330                     VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
331                 }
332 #endif // __WITH_X509__
333             }
334
335             //PublicData is mandatory only for SIGNED_ASYMMETRIC_KEY credentials type.
336             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PUBLICDATA_NAME);
337 #ifdef __WITH_X509__
338             if (cred->credType & SIGNED_ASYMMETRIC_KEY)
339             {
340                 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
341                 VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
342             }
343 #endif //  __WITH_X509__
344             if (NULL != jsonObj)
345             {
346                 if (cJSON_String == jsonObj->type)
347                 {
348                     jsonObjLen = strlen(jsonObj->valuestring) + 1;
349                     cred->publicData.data = (char *)OICMalloc(jsonObjLen);
350                     VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
351                     strncpy((char *)cred->publicData.data, (char *)jsonObj->valuestring, jsonObjLen);
352                 }
353 #ifdef __WITH_X509__
354                 else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
355                 {
356                     cred->publicData.data = cJSON_PrintUnformatted(jsonObj);
357                     VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
358                 }
359 #endif //  __WITH_X509__
360             }
361
362             //Period -- Not Mandatory
363             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
364             if(jsonObj && cJSON_String == jsonObj->type)
365             {
366                 jsonObjLen = strlen(jsonObj->valuestring) + 1;
367                 cred->period = (char *)OICMalloc(jsonObjLen);
368                 VERIFY_NON_NULL(TAG, cred->period, ERROR);
369                 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
370             }
371
372             //Owners -- Mandatory
373             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
374             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
375             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
376             cred->ownersLen = cJSON_GetArraySize(jsonObj);
377             VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
378             cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
379             VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
380             for(size_t i = 0; i < cred->ownersLen; i++)
381             {
382                 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
383                 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
384                 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
385                 outLen = 0;
386                 memset(base64Buff, 0, sizeof(base64Buff));
387                 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
388                          base64Buff, sizeof(base64Buff), &outLen);
389                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
390                                outLen <= sizeof(cred->owners[i].id)), ERROR);
391                 memcpy(cred->owners[i].id, base64Buff, outLen);
392             }
393             prevCred = cred;
394         } while( ++idx < numCred);
395     }
396
397     ret = OC_STACK_OK;
398
399 exit:
400     cJSON_Delete(jsonRoot);
401     if (OC_STACK_OK != ret)
402     {
403         DeleteCredList(headCred);
404         headCred = NULL;
405     }
406     return headCred;
407 }
408
409 /**
410  * This function generates the bin credential data.
411  *
412  * @param subject pointer to subject of this credential.
413  * @param credType credential type.
414  * @param publicData public data such as public key.
415  * @param privateData private data such as private key.
416  *        The privateData is expected in base64 encoded format.
417  * @param ownersLen length of owners array
418  * @param owners array of owners.
419  *
420  * @retval
421  *      pointer to instance of OicSecCred_t  - success
422  *      NULL                                 - error
423  */
424 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
425                                  const char * publicData, const char * privateData,
426                                  size_t ownersLen, const OicUuid_t * owners)
427 {
428     (void)publicData;
429     OCStackResult ret = OC_STACK_ERROR;
430
431     OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
432     VERIFY_NON_NULL(TAG, cred, ERROR);
433
434     //CredId is assigned before appending new cred to the existing
435     //credential list and updating svr database in AddCredential().
436     cred->credId = 0;
437
438     VERIFY_NON_NULL(TAG, subject, ERROR);
439     memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
440
441     VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
442             SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
443     cred->credType = credType;
444
445 #ifdef __WITH_X509__
446     if(publicData)
447     {
448         cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
449         VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
450         strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
451     }
452 #endif // __WITH_X509__
453
454     if(privateData)
455     {
456         cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
457         VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
458         strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
459     }
460
461     VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
462     cred->ownersLen = ownersLen;
463
464     cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
465     VERIFY_NON_NULL(TAG, cred->owners, ERROR);
466     for(size_t i = 0; i < cred->ownersLen; i++)
467     {
468         memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
469     }
470
471     ret = OC_STACK_OK;
472 exit:
473     if (OC_STACK_OK != ret)
474     {
475         DeleteCredList(cred);
476         cred = NULL;
477     }
478     return cred;
479 }
480
481 static bool UpdatePersistentStorage(const OicSecCred_t *cred)
482 {
483     bool ret = false;
484
485     // Convert Cred data into JSON for update to persistent storage
486     char *jsonStr = BinToCredJSON(cred);
487     if (jsonStr)
488     {
489         cJSON *jsonCred = cJSON_Parse(jsonStr);
490         OICFree(jsonStr);
491
492         if ((jsonCred) &&
493           (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
494         {
495             ret = true;
496         }
497         cJSON_Delete(jsonCred );
498     }
499     else //Empty cred list
500     {
501         if (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, NULL))
502         {
503             ret = true;
504         }
505     }
506     return ret;
507 }
508
509 /**
510  * Compare function used LL_SORT for sorting credentials
511  *
512  * @param first   pointer to OicSecCred_t struct
513  * @param second  pointer to OicSecCred_t struct
514  *
515  *@retval
516  *  -1    if credId of first is less than credId of second
517  *   0    if credId of first is equal to credId of second
518  *   1    if credId of first is greater than credId of second
519  */
520 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
521 {
522     if(first->credId < second->credId)
523     {
524         return -1;
525     }
526     else if(first->credId > second->credId)
527     {
528         return 1;
529     }
530     else
531         return 0;
532 }
533
534 /**
535  * GetCredId goes through the cred list and returns the next
536  * available credId. The next credId could be the credId that is
537  * available due deletion of OicSecCred_t object or one more than
538  * credId of last credential in the list.
539  *
540  * @retval
541  *      next available credId  - success
542  *      0                      - error
543  */
544
545 static uint16_t GetCredId()
546 {
547     //Sorts credential list in incremental order of credId
548     LL_SORT(gCred, CmpCredId);
549
550
551     OicSecCred_t *currentCred = NULL, *credTmp = NULL;
552     uint16_t nextCredId = 1;
553
554     LL_FOREACH_SAFE(gCred, currentCred, credTmp)
555     {
556         if(currentCred->credId == nextCredId)
557         {
558             nextCredId += 1;
559         }
560         else
561         {
562             break;
563         }
564     }
565
566     VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
567     return nextCredId;
568
569 exit:
570     return 0;
571 }
572
573 /**
574  * Get the default value
575  * @retval  NULL for now. Update it when we finalize the default info.
576  */
577 static OicSecCred_t* GetCredDefault()
578 {
579     return NULL;
580 }
581
582 /**
583  * This function adds the new cred to the credential list.
584  *
585  * @param cred pointer to new credential.
586  *
587  * @retval
588  *      OC_STACK_OK     - cred not NULL and persistent storage gets updated
589  *      OC_STACK_ERROR  - cred is NULL or fails to update persistent storage
590  */
591 OCStackResult AddCredential(OicSecCred_t * newCred)
592 {
593     OCStackResult ret = OC_STACK_ERROR;
594
595     VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
596
597     //Assigning credId to the newCred
598     newCred->credId = GetCredId();
599
600     VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
601
602     //Append the new Cred to existing list
603     LL_APPEND(gCred, newCred);
604
605     if(UpdatePersistentStorage(gCred))
606     {
607         ret = OC_STACK_OK;
608     }
609
610 exit:
611     return ret;
612 }
613
614 OCStackResult RemoveCredential(const OicUuid_t *subject)
615 {
616     OCStackResult ret = OC_STACK_ERROR;
617     OicSecCred_t *cred = NULL;
618     OicSecCred_t *tempCred = NULL;
619     bool deleteFlag = false;
620
621     LL_FOREACH_SAFE(gCred, cred, tempCred)
622     {
623         if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
624         {
625             LL_DELETE(gCred, cred);
626             FreeCred(cred);
627             deleteFlag = 1;
628         }
629     }
630
631     if(deleteFlag)
632     {
633         if(UpdatePersistentStorage(gCred))
634         {
635             ret = OC_STACK_RESOURCE_DELETED;
636         }
637     }
638     return ret;
639
640 }
641
642 /**
643  * Remove all credential data on credential resource and persistent storage
644  *
645  * @retval
646  *     OC_STACK_OK              - no errors
647  *     OC_STACK_ERROR           - stack process error
648  */
649 OCStackResult RemoveAllCredentials(void)
650 {
651     DeleteCredList(gCred);
652     gCred = GetCredDefault();
653
654     if(!UpdatePersistentStorage(gCred))
655     {
656         return OC_STACK_ERROR;
657     }
658     return OC_STACK_OK;
659 }
660
661 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
662 {
663     OCEntityHandlerResult ret = OC_EH_ERROR;
664
665     //Get binary representation of json
666     OicSecCred_t * cred  = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
667
668     if(cred)
669     {
670         //If the Post request credential has credId, it will be
671         //discarded and the next available credId will be assigned
672         //to it before getting appended to the existing credential
673         //list and updating svr database.
674         ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
675     }
676     return ret;
677 }
678
679 static OCEntityHandlerResult HandleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
680 {
681     OC_LOG(DEBUG, TAG, "Processing CredDeleteRequest");
682
683     OCEntityHandlerResult ehRet = OC_EH_ERROR;
684
685     if(NULL == ehRequest->query)
686    {
687        return ehRet;
688    }
689
690    OicParseQueryIter_t parseIter = {.attrPos=NULL};
691    OicUuid_t subject = {.id={0}};
692
693    //Parsing REST query to get the subject
694    ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
695    while(GetNextQuery(&parseIter))
696    {
697        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME,
698                parseIter.attrLen) == 0)
699        {
700            unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
701            uint32_t outLen = 0;
702            B64Result b64Ret = B64_OK;
703
704            b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen,
705                    base64Buff, sizeof(base64Buff), &outLen);
706
707            VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
708            memcpy(subject.id, base64Buff, outLen);
709        }
710    }
711
712    if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&subject))
713    {
714        ehRet = OC_EH_RESOURCE_DELETED;
715    }
716
717 exit:
718     return ehRet;
719 }
720
721 /*
722  * This internal method is the entity handler for Cred resources
723  * to handle REST request (PUT/POST/DEL)
724  */
725 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
726                                         OCEntityHandlerRequest * ehRequest,
727                                         void* callbackParameter)
728 {
729     (void)callbackParameter;
730     OCEntityHandlerResult ret = OC_EH_ERROR;
731
732     if(!ehRequest)
733     {
734         return OC_EH_ERROR;
735     }
736     if (flag & OC_REQUEST_FLAG)
737     {
738         OC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
739         //TODO :  Handle PUT/DEL methods
740         switch(ehRequest->method)
741         {
742             case OC_REST_GET:
743                 ret = OC_EH_FORBIDDEN;
744                 break;
745             case OC_REST_POST:
746                 ret = HandlePostRequest(ehRequest);
747                 break;
748             case OC_REST_DELETE:
749                 ret = HandleDeleteRequest(ehRequest);
750                 break;
751             default:
752                 ret = OC_EH_ERROR;
753                 break;
754         }
755     }
756
757     //Send payload to request originator
758     ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
759                        ret : OC_EH_ERROR);
760
761     return ret;
762 }
763
764 /*
765  * This internal method is used to create '/oic/sec/Cred' resource.
766  */
767 OCStackResult CreateCredResource()
768 {
769     OCStackResult ret;
770
771     ret = OCCreateResource(&gCredHandle,
772                            OIC_RSRC_TYPE_SEC_CRED,
773                            OIC_MI_DEF,
774                            OIC_RSRC_CRED_URI,
775                            CredEntityHandler,
776                            NULL,
777                            OC_RES_PROP_NONE);
778
779     if (OC_STACK_OK != ret)
780     {
781         OC_LOG (FATAL, TAG, "Unable to instantiate Cred resource");
782         DeInitCredResource();
783     }
784     return ret;
785 }
786
787 /**
788  * Initialize Cred resource by loading data from persistent storage.
789  *
790  * @retval
791  *     OC_STACK_OK    - no errors
792  *     OC_STACK_ERROR - stack process error
793  */
794 OCStackResult InitCredResource()
795 {
796     OCStackResult ret = OC_STACK_ERROR;
797
798     //Read Cred resource from PS
799     char* jsonSVRDatabase = GetSVRDatabase();
800
801     if (jsonSVRDatabase)
802     {
803         //Convert JSON Cred into binary format
804         gCred = JSONToCredBin(jsonSVRDatabase);
805     }
806     /*
807      * If SVR database in persistent storage got corrupted or
808      * is not available for some reason, a default Cred is created
809      * which allows user to initiate Cred provisioning again.
810      */
811     if (!jsonSVRDatabase || !gCred)
812     {
813         gCred = GetCredDefault();
814     }
815     //Instantiate 'oic.sec.cred'
816     ret = CreateCredResource();
817     OICFree(jsonSVRDatabase);
818     return ret;
819 }
820
821 /**
822  * Perform cleanup for Cred resources.
823  *
824  * @return
825  *     OC_STACK_OK              - no errors
826  *     OC_STACK_ERROR           - stack process error
827  *     OC_STACK_NO_RESOURCE     - resource not found
828  *     OC_STACK_INVALID_PARAM   - invalid param
829  */
830 OCStackResult DeInitCredResource()
831 {
832     OCStackResult result = OCDeleteResource(gCredHandle);
833     DeleteCredList(gCred);
834     gCred = NULL;
835     return result;
836 }
837
838 /**
839  * This method is used by tinydtls/SRM to retrieve credential for given Subject.
840  *
841  * @param subject - subject for which credential is required.
842  *
843  * @retval
844  *     reference to OicSecCred_t - if credential is found
845  *     NULL                      - if credential not found
846  */
847 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
848 {
849     OicSecCred_t *cred = NULL;
850
851    if ( NULL == subject)
852     {
853        return NULL;
854     }
855
856     LL_FOREACH(gCred, cred)
857     {
858         if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
859         {
860             return cred;
861         }
862     }
863     return NULL;
864 }
865
866
867 #if defined(__WITH_DTLS__)
868 /**
869  * This internal callback is used by lower stack (i.e. CA layer) to
870  * retrieve PSK credentials from RI security layer.
871  *
872  * @param[in]  type type of PSK data required by tinyDTLS layer during DTLS handshake.
873  * @param[in]  desc Additional request information.
874  * @param[in]  desc_len The actual length of desc.
875  * @param[out] result  Must be filled with the requested information.
876  * @param[in]  result_length  Maximum size of @p result.
877  *
878  * @return The number of bytes written to @p result or a value
879  *         less than zero on error.
880  */
881 int32_t GetDtlsPskCredentials( CADtlsPskCredType_t type,
882               const unsigned char *desc, size_t desc_len,
883               unsigned char *result, size_t result_length)
884 {
885     int32_t ret = -1;
886
887     if (NULL == result)
888     {
889         return ret;
890     }
891
892     switch (type)
893     {
894         case CA_DTLS_PSK_HINT:
895         case CA_DTLS_PSK_IDENTITY:
896             {
897                 OicUuid_t deviceID = {.id={}};
898                 // Retrieve Device ID from doxm resource
899                 if ( OC_STACK_OK != GetDoxmDeviceID(&deviceID) )
900                 {
901                     OC_LOG (ERROR, TAG, "Unable to retrieve doxm Device ID");
902                     return ret;
903                 }
904
905                 if (result_length < sizeof(deviceID.id))
906                 {
907                     OC_LOG (ERROR, TAG, "Wrong value for result_length");
908                     return ret;
909                 }
910                 memcpy(result, deviceID.id, sizeof(deviceID.id));
911                 return (sizeof(deviceID.id));
912             }
913             break;
914
915         case CA_DTLS_PSK_KEY:
916             {
917                 OicSecCred_t *cred = NULL;
918                 LL_FOREACH(gCred, cred)
919                 {
920                     if (cred->credType != SYMMETRIC_PAIR_WISE_KEY)
921                     {
922                         continue;
923                     }
924
925                     if ((desc_len == sizeof(cred->subject.id)) &&
926                         (memcmp(desc, cred->subject.id, sizeof(cred->subject.id)) == 0))
927                     {
928                         /*
929                          * If the credentials are valid for limited time,
930                          * check their expiry.
931                          */
932                         if (cred->period)
933                         {
934                             if(IOTVTICAL_VALID_ACCESS != IsRequestWithinValidTime(cred->period, NULL))
935                             {
936                                 OC_LOG (INFO, TAG, "Credentials are expired.");
937                                 ret = -1;
938                                 return ret;
939                             }
940                         }
941
942                         // Convert PSK from Base64 encoding to binary before copying
943                         uint32_t outLen = 0;
944                         B64Result b64Ret = b64Decode(cred->privateData.data,
945                                 strlen(cred->privateData.data), result,
946                                 result_length, &outLen);
947                         if (B64_OK != b64Ret)
948                         {
949                             OC_LOG (ERROR, TAG, "Base64 decoding failed.");
950                             ret = -1;
951                             return ret;
952                         }
953                         return outLen;
954                     }
955                 }
956             }
957             break;
958
959         default:
960             {
961                 OC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
962                 ret = -1;
963             }
964             break;
965     }
966
967     return ret;
968 }
969
970 /**
971  * Add temporal PSK to PIN based OxM
972  *
973  * @param[in] tmpSubject UUID of target device
974  * @param[in] credType Type of credential to be added
975  * @param[in] pin numeric characters
976  * @param[in] pinSize length of 'pin'
977  * @param[in] ownersLen Number of owners
978  * @param[in] owners Array of owners
979  * @param[out] tmpCredSubject Generated credential's subject.
980  *
981  * @return OC_STACK_OK for success and errorcode otherwise.
982  */
983 OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t credType,
984                             const char * pin, size_t pinSize,
985                             size_t ownersLen, const OicUuid_t * owners, OicUuid_t* tmpCredSubject)
986 {
987     OCStackResult ret = OC_STACK_ERROR;
988
989     if(tmpSubject == NULL || pin == NULL || pinSize == 0 || tmpCredSubject == NULL)
990     {
991         return OC_STACK_INVALID_PARAM;
992     }
993
994     uint8_t privData[OWNER_PSK_LENGTH_128] = {0,};
995     int dtlsRes = DeriveCryptoKeyFromPassword((const unsigned char *)pin, pinSize, owners->id,
996                                               UUID_LENGTH, PBKDF_ITERATIONS,
997                                               OWNER_PSK_LENGTH_128, privData);
998     VERIFY_SUCCESS(TAG, (dtlsRes == 0) , ERROR);
999
1000     uint32_t outLen = 0;
1001     char base64Buff[B64ENCODE_OUT_SAFESIZE(OWNER_PSK_LENGTH_128) + 1] = {};
1002     B64Result b64Ret = b64Encode(privData, OWNER_PSK_LENGTH_128, base64Buff,
1003                                 sizeof(base64Buff), &outLen);
1004     VERIFY_SUCCESS(TAG, (B64_OK == b64Ret), ERROR);
1005
1006     OicSecCred_t* cred = GenerateCredential(tmpSubject, credType, NULL,
1007                                             base64Buff, ownersLen, owners);
1008     if(NULL == cred)
1009     {
1010         OC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to generate credential");
1011         return OC_STACK_ERROR;
1012     }
1013
1014     memcpy(tmpCredSubject->id, cred->subject.id, UUID_LENGTH);
1015
1016     ret = AddCredential(cred);
1017     if( OC_STACK_OK != ret)
1018     {
1019         OC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to add credential");
1020     }
1021
1022 exit:
1023     return ret;
1024 }
1025
1026 #endif /* __WITH_DTLS__ */
1027 #ifdef __WITH_X509__
1028 #define CERT_LEN_PREFIX (3)
1029 #define BYTE_SIZE (8) //bits
1030 #define PUB_KEY_X_COORD ("x")
1031 #define PUB_KEY_Y_COORD ("y")
1032 #define CERTIFICATE ("x5c")
1033 #define PRIVATE_KEY ("d")
1034
1035
1036 static void WriteCertPrefix(uint8_t *prefix, uint32_t certLen)
1037 {
1038     for (size_t i = 0; i < CERT_LEN_PREFIX; ++i)
1039     {
1040         prefix[i] = (certLen >> (BYTE_SIZE * (CERT_LEN_PREFIX - 1 - i))) & 0xFF;
1041     }
1042 }
1043
1044 static uint32_t ParseCertPrefix(uint8_t *prefix)
1045 {
1046     uint32_t res = 0;
1047     if(NULL != prefix)
1048     {
1049         for(int i=0; i < CERT_LEN_PREFIX; ++i)
1050         {
1051             res |= (((uint32_t) prefix[i]) << ((CERT_LEN_PREFIX - 1 -i) * BYTE_SIZE));
1052         }
1053     }
1054     return res;
1055 }
1056
1057 static uint32_t appendCert2Chain(uint8_t *appendPoint, char *cert, uint32_t max_len)
1058 {
1059     uint32_t ret = 0;
1060     VERIFY_NON_NULL(TAG, appendPoint, ERROR);
1061     VERIFY_NON_NULL(TAG, cert, ERROR);
1062
1063     uint32_t certLen;
1064     VERIFY_SUCCESS(TAG, B64_OK == b64Decode(cert, strlen(cert), appendPoint + CERT_LEN_PREFIX,
1065                                             max_len - CERT_LEN_PREFIX, &certLen), ERROR);
1066     WriteCertPrefix(appendPoint, certLen);
1067
1068     ret = certLen + CERT_LEN_PREFIX;
1069 exit:
1070     return ret;
1071 }
1072
1073 static OCStackResult GetCAPublicKeyData(CADtlsX509Creds_t *credInfo){
1074     OCStackResult ret = OC_STACK_ERROR;
1075     uint8_t *ccPtr = credInfo->certificateChain;
1076     for(uint32_t i =0; i < credInfo->chainLen - 1; ++i)
1077     {
1078         ccPtr += CERT_LEN_PREFIX + ParseCertPrefix(ccPtr);
1079     }
1080
1081     ByteArray cert = {
1082         .data = ccPtr + CERT_LEN_PREFIX,
1083         .len = ParseCertPrefix(ccPtr)
1084          };
1085     CertificateX509 certStruct;
1086
1087     VERIFY_SUCCESS(TAG, PKI_SUCCESS == DecodeCertificate(cert, &certStruct), ERROR);
1088
1089     INC_BYTE_ARRAY(certStruct.pubKey, 2);
1090
1091     memcpy(credInfo->rootPublicKeyX, certStruct.pubKey.data, PUBLIC_KEY_SIZE / 2);
1092     memcpy(credInfo->rootPublicKeyY, certStruct.pubKey.data + PUBLIC_KEY_SIZE / 2, PUBLIC_KEY_SIZE / 2);
1093
1094     ret = OC_STACK_OK;
1095     exit:
1096     return ret;
1097 }
1098
1099 static OCStackResult GetCertCredPublicData(CADtlsX509Creds_t *credInfo, OicSecCred_t *cred)
1100 {
1101     OCStackResult ret = OC_STACK_ERROR;
1102     VERIFY_NON_NULL(TAG, credInfo, ERROR);
1103     VERIFY_NON_NULL(TAG, cred, ERROR);
1104     VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
1105     //VERIFY_SUCCESS(TAG, NULL == credInfo->certificateChain.data, ERROR);
1106     cJSON *jsonRoot = cJSON_Parse(cred->publicData.data);
1107     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
1108
1109     //Get certificate chain
1110     cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, CERTIFICATE);//TODO define field names constants
1111     VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_Array == jsonObj->type, ERROR);
1112
1113     size_t certChainLen = cJSON_GetArraySize(jsonObj);
1114     credInfo->chainLen = certChainLen;
1115     VERIFY_SUCCESS(TAG, MAX_CHAIN_LEN >= certChainLen, ERROR);
1116
1117     uint32_t len = 0;
1118     for (size_t i = 0; i < certChainLen; ++i)
1119     {
1120         cJSON *item = cJSON_GetArrayItem(jsonObj, i);
1121         VERIFY_SUCCESS(TAG, cJSON_String == item->type, ERROR);
1122         uint32_t appendedLen = appendCert2Chain(credInfo->certificateChain + len, item->valuestring,
1123                                               MAX_CERT_MESSAGE_LEN - len);
1124         VERIFY_SUCCESS(TAG, 0 != appendedLen, ERROR);
1125         len += appendedLen;
1126     }
1127     credInfo->certificateChainLen = len;
1128     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCAPublicKeyData(credInfo), ERROR);
1129     ret = OC_STACK_OK;
1130 exit:
1131     cJSON_Delete(jsonRoot);
1132     return ret;
1133 }
1134
1135 static OCStackResult GetCertCredPrivateData(CADtlsX509Creds_t *credInfo, OicSecCred_t *cred)
1136 {
1137     OCStackResult ret = OC_STACK_ERROR;
1138     VERIFY_NON_NULL(TAG, credInfo, ERROR);
1139     VERIFY_NON_NULL(TAG, cred, ERROR);
1140     VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
1141     cJSON *jsonRoot = cJSON_Parse(cred->privateData.data);
1142     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
1143
1144     cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, PRIVATE_KEY);//TODO define field names constants
1145     VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_String == jsonObj->type, ERROR);
1146
1147     uint32_t read = 0u;
1148     VERIFY_SUCCESS(TAG, B64_OK == b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
1149                                             credInfo->devicePrivateKey, PRIVATE_KEY_SIZE, &read)
1150                    && PRIVATE_KEY_SIZE == read, ERROR);
1151
1152     ret = OC_STACK_OK;
1153
1154 exit:
1155     cJSON_Delete(jsonRoot);
1156     return ret;
1157 }
1158
1159 int GetDtlsX509Credentials(CADtlsX509Creds_t *credInfo)
1160 {
1161     int ret = 1;
1162     VERIFY_NON_NULL(TAG, credInfo, ERROR);
1163     if (NULL == gCred)
1164     {
1165         VERIFY_SUCCESS(TAG, OC_STACK_OK == InitCredResource(), ERROR);
1166     }
1167
1168     OicSecCred_t *cred = NULL;
1169     LL_SEARCH_SCALAR(gCred, cred, credType, SIGNED_ASYMMETRIC_KEY);
1170     VERIFY_NON_NULL(TAG, cred, ERROR);
1171
1172     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPrivateData(credInfo, cred), ERROR);
1173     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPublicData(credInfo, cred), ERROR);
1174
1175     ret = 0;
1176 exit:
1177
1178     return ret;
1179 }
1180 #undef CERT_LEN_PREFIX
1181 #endif /* __WITH_X509__ */