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