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