Imported Upstream version 0.9.2
[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 <stdlib.h>
37 #include <string.h>
38 #include <stdint.h>
39
40
41 #define TAG  PCF("SRM-CREDL")
42
43 static OicSecCred_t        *gCred = NULL;
44 static OCResourceHandle    gCredHandle = NULL;
45
46 void DeleteCredList(OicSecCred_t* cred)
47 {
48     if (cred)
49     {
50         OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
51         LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
52         {
53             LL_DELETE(cred, credTmp1);
54
55             //Note: Need further clarification on roleID data type
56 #if 0
57             //Clean roleIds
58             OICFree(credTmp1->roleIds);
59 #endif
60
61             //Clean PublicData
62             OICFree(credTmp1->publicData.data);
63
64             //Clean PrivateData
65             OICFree(credTmp1->privateData.data);
66
67             //Clean Period
68             OICFree(credTmp1->period);
69
70             //Clean Owners
71             OICFree(credTmp1->owners);
72
73             //Clean Cred node itself
74             OICFree(credTmp1);
75         }
76     }
77 }
78
79 /**
80  * This function converts credential data into JSON format.
81  * Caller needs to invoke 'free' when done using
82  * returned string.
83  * @param cred  pointer to instance of OicSecCred_t structure.
84  *
85  * @retval
86  *      pointer to JSON credential representation - if credential for subjectId found
87  *      NULL                                      - if credential for subjectId not found
88  */
89 char * BinToCredJSON(const OicSecCred_t * cred)
90 {
91     cJSON *jsonRoot = NULL;
92     char *jsonStr = NULL;
93
94     if (cred)
95     {
96         char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
97         uint32_t outLen = 0;
98         B64Result b64Ret = B64_OK;
99
100         jsonRoot = cJSON_CreateObject();
101         VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
102
103         cJSON *jsonCredArray = NULL;
104         cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
105                 jsonCredArray = cJSON_CreateArray());
106         VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
107
108         while(cred)
109         {
110             cJSON *jsonCred = cJSON_CreateObject();
111             VERIFY_NON_NULL(TAG, jsonCred, ERROR);
112
113             //CredID -- Mandatory
114             cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
115
116             //Subject -- Mandatory
117             outLen = 0;
118             memset(base64Buff, 0, sizeof(base64Buff));
119             b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
120                    sizeof(base64Buff), &outLen);
121             VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
122             cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
123
124             //Note: Need further clarification on roleID data type
125 #if 0
126             //RoleId -- Not Mandatory
127             if(cred->roleIdsLen > 0)
128             {
129                 cJSON *jsonRoleIdsArray = NULL;
130                 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
131                                          jsonRoleIdsArray = cJSON_CreateArray());
132                 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
133                 for (size_t i = 0; i < cred->roleIdsLen; i++)
134                 {
135                     cJSON_AddItemToArray (jsonRoleIdsArray,
136                             cJSON_CreateString((char *)cred->roleIds[i].id));
137                 }
138             }
139 #endif
140
141             //CredType -- Mandatory
142             cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
143
144 #if 0
145             //PublicData -- Not Mandatory
146             if(cred->publicData.data)
147             {
148                 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
149             }
150 #endif
151             //PrivateData -- Not Mandatory
152             if(cred->privateData.data)
153             {
154                 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
155             }
156
157             //Period -- Not Mandatory
158             if(cred->period)
159             {
160                 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
161                                         cred->period);
162             }
163
164             //Owners -- Mandatory
165             cJSON *jsonOwnrArray = NULL;
166             cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
167                                              jsonOwnrArray = cJSON_CreateArray());
168             VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
169             for (size_t i = 0; i < cred->ownersLen; i++)
170             {
171                 outLen = 0;
172                 memset(base64Buff, 0, sizeof(base64Buff));
173                 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
174                         base64Buff, sizeof(base64Buff), &outLen);
175                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
176                 cJSON_AddItemToArray (jsonOwnrArray,
177                                        cJSON_CreateString((char *)(base64Buff)));
178             }
179
180             /* Attach current cred node to cred Array */
181             cJSON_AddItemToArray(jsonCredArray, jsonCred);
182             cred = cred->next;
183         }
184
185         jsonStr = cJSON_PrintUnformatted(jsonRoot);
186     }
187
188 exit:
189     if (jsonRoot)
190     {
191         cJSON_Delete(jsonRoot);
192     }
193     return jsonStr;
194 }
195
196 /*
197  * This internal method converts JSON cred into binary cred.
198  */
199 OicSecCred_t * JSONToCredBin(const char * jsonStr)
200 {
201     OCStackResult ret = OC_STACK_ERROR;
202     OicSecCred_t * headCred = NULL;
203     OicSecCred_t * prevCred = NULL;
204     cJSON *jsonCredArray = NULL;
205
206     cJSON *jsonRoot = cJSON_Parse(jsonStr);
207     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
208
209     jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
210     VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
211     if (cJSON_Array == jsonCredArray->type)
212     {
213         int numCred = cJSON_GetArraySize(jsonCredArray);
214         int idx = 0;
215
216         unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
217         uint32_t outLen = 0;
218         B64Result b64Ret = B64_OK;
219
220         VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
221         do
222         {
223             cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
224             VERIFY_NON_NULL(TAG, jsonCred, ERROR);
225
226             OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
227             VERIFY_NON_NULL(TAG, cred, ERROR);
228
229             headCred = (headCred) ? headCred : cred;
230             if (prevCred)
231             {
232                 prevCred->next = cred;
233             }
234             size_t jsonObjLen = 0;
235             cJSON *jsonObj = NULL;
236
237             //CredId -- Mandatory
238             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
239             if(jsonObj)
240             {
241                 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
242                 cred->credId = jsonObj->valueint;
243             }
244
245             //subject -- Mandatory
246             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
247             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
248             VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
249             outLen = 0;
250             memset(base64Buff, 0, sizeof(base64Buff));
251             b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
252                     base64Buff, sizeof(base64Buff), &outLen);
253             VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
254                            ERROR);
255             memcpy(cred->subject.id, base64Buff, outLen);
256
257             //CredType -- Mandatory
258             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
259             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
260             VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
261             cred->credType = jsonObj->valueint;
262
263             //PrivateData is mandatory for some of the credential types listed below.
264             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
265             if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
266                 (cred->credType & SYMMETRIC_GROUP_KEY) ||
267                 (cred->credType & PIN_PASSWORD))
268             {
269                 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
270                 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
271             }
272             if(jsonObj && cJSON_String == jsonObj->type)
273             {
274                 jsonObjLen = strlen(jsonObj->valuestring) + 1;
275                 cred->privateData.data = (char *)OICMalloc(jsonObjLen);
276                 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
277                 strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
278             }
279
280             //Period -- Not Mandatory
281             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
282             if(jsonObj && cJSON_String == jsonObj->type)
283             {
284                 jsonObjLen = strlen(jsonObj->valuestring) + 1;
285                 cred->period = (char *)OICMalloc(jsonObjLen);
286                 VERIFY_NON_NULL(TAG, cred->period, ERROR);
287                 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
288             }
289
290             //Owners -- Mandatory
291             jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
292             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
293             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR)
294             cred->ownersLen = cJSON_GetArraySize(jsonObj);
295             VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
296             cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
297             VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
298             for(size_t i = 0; i < cred->ownersLen; i++)
299             {
300                 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
301                 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
302                 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
303                 outLen = 0;
304                 memset(base64Buff, 0, sizeof(base64Buff));
305                 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
306                          base64Buff, sizeof(base64Buff), &outLen);
307                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
308                                outLen <= sizeof(cred->owners[i].id)), ERROR);
309                 memcpy(cred->owners[i].id, base64Buff, outLen);
310             }
311             prevCred = cred;
312         } while( ++idx < numCred);
313     }
314
315     ret = OC_STACK_OK;
316
317 exit:
318     cJSON_Delete(jsonRoot);
319     if (OC_STACK_OK != ret)
320     {
321         DeleteCredList(headCred);
322         headCred = NULL;
323     }
324     return headCred;
325 }
326
327 /**
328  * This function generates the bin credential data.
329  *
330  * @param subject pointer to subject of this credential.
331  * @param credType credential type.
332  * @param publicData public data such as public key.
333  * @param privateData private data such as private key.
334  *        The privateData is expected in base64 encoded format.
335  * @param ownersLen length of owners array
336  * @param owners array of owners.
337  *
338  * @retval
339  *      pointer to instance of OicSecCred_t  - success
340  *      NULL                                 - error
341  */
342 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
343                                  const char * publicData, const char * privateData,
344                                  size_t ownersLen, const OicUuid_t * owners)
345 {
346     OCStackResult ret = OC_STACK_ERROR;
347
348     OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
349     VERIFY_NON_NULL(TAG, cred, ERROR);
350
351     //CredId is assigned before appending new cred to the existing
352     //credential list and updating svr database in AddCredential().
353     cred->credId = 0;
354
355     VERIFY_NON_NULL(TAG, subject, ERROR);
356     memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
357
358     VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
359             SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
360     cred->credType = credType;
361
362 #if 0
363     if(publicData)
364     {
365         cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
366         VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
367         strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
368     }
369 #endif
370
371     if(privateData)
372     {
373         cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
374         VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
375         strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
376     }
377
378     VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
379     cred->ownersLen = ownersLen;
380
381     cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
382     VERIFY_NON_NULL(TAG, cred->owners, ERROR);
383     for(size_t i = 0; i < cred->ownersLen; i++)
384     {
385         memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
386     }
387
388     ret = OC_STACK_OK;
389 exit:
390     if (OC_STACK_OK != ret)
391     {
392         DeleteCredList(cred);
393         cred = NULL;
394     }
395     return cred;
396 }
397
398 /*
399  * Compare function used LL_SORT for sorting credentials
400  *
401  * @param first   pointer to OicSecCred_t struct
402  * @param second  pointer to OicSecCred_t struct
403  *
404  *@retval
405  *  -1    if credId of first is less than credId of second
406  *   0    if credId of first is equal to credId of second
407  *   1    if credId of first is greater than credId of second
408  */
409 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
410 {
411     if(first->credId < second->credId)
412     {
413         return -1;
414     }
415     else if(first->credId > second->credId)
416     {
417         return 1;
418     }
419     else
420         return 0;
421 }
422
423 /**
424  * GetCredId goes through the cred list and returns the next
425  * available credId. The next credId could be the credId that is
426  * available due deletion of OicSecCred_t object or one more than
427  * credId of last credential in the list.
428  *
429  * @retval
430  *      next available credId  - success
431  *      0                      - error
432  */
433
434 static uint16_t GetCredId()
435 {
436     //Sorts credential list in incremental order of credId
437     LL_SORT(gCred, CmpCredId);
438
439
440     OicSecCred_t *currentCred = NULL, *credTmp = NULL;
441     uint16_t nextCredId = 1;
442
443     LL_FOREACH_SAFE(gCred, currentCred, credTmp)
444     {
445         if(currentCred->credId == nextCredId)
446         {
447             nextCredId += 1;
448         }
449         else
450         {
451             break;
452         }
453     }
454
455     VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
456     return nextCredId;
457
458 exit:
459     return 0;
460 }
461 /**
462  * This function adds the new cred to the credential list.
463  *
464  * @param cred pointer to new credential.
465  *
466  * @retval
467  *      OC_STACK_OK     - cred not NULL and persistent storage gets updated
468  *      OC_STACK_ERROR  - cred is NULL or fails to update persistent storage
469  */
470 OCStackResult AddCredential(OicSecCred_t * newCred)
471 {
472     OCStackResult ret = OC_STACK_ERROR;
473     char * jsonStr = NULL;
474
475     VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
476
477     //Assigning credId to the newCred
478     newCred->credId = GetCredId();
479
480     VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
481
482     //Append the new Cred to existing list
483     LL_APPEND(gCred, newCred);
484
485     //Convert CredList to JSON and update the persistent Storage
486     jsonStr = BinToCredJSON(gCred);
487
488     if(jsonStr)
489     {
490         cJSON *jsonCred = cJSON_Parse(jsonStr);
491         OICFree(jsonStr);
492
493         if((jsonCred) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
494         {
495             ret = OC_STACK_OK;
496         }
497         cJSON_Delete(jsonCred);
498     }
499
500 exit:
501     return ret;
502 }
503
504 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
505 {
506     OCEntityHandlerResult ret = OC_EH_ERROR;
507
508     //Get binary representation of json
509     OicSecCred_t * cred  = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
510
511     if(cred)
512     {
513         //If the Post request credential has credId, it will be
514         //discarded and the next available credId will be assigned
515         //to it before getting appended to the existing credential
516         //list and updating svr database.
517         ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
518     }
519
520     return ret;
521 }
522
523 /*
524  * This internal method is the entity handler for Cred resources
525  * to handle REST request (PUT/POST/DEL)
526  */
527 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
528                                         OCEntityHandlerRequest * ehRequest,
529                                         void* callbackParameter)
530 {
531     OCEntityHandlerResult ret = OC_EH_ERROR;
532
533     if(!ehRequest)
534     {
535         return OC_EH_ERROR;
536     }
537     if (flag & OC_REQUEST_FLAG)
538     {
539         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
540         //TODO :  Handle PUT/DEL methods
541         switch(ehRequest->method)
542         {
543             case OC_REST_GET:
544                 ret = OC_EH_FORBIDDEN;
545                 break;
546             case OC_REST_POST:
547                 ret = HandlePostRequest(ehRequest);
548                 break;
549             default:
550                 ret = OC_EH_ERROR;
551                 break;
552         }
553     }
554
555     //Send payload to request originator
556     ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
557                        ret : OC_EH_ERROR);
558
559     return ret;
560 }
561
562 /*
563  * This internal method is used to create '/oic/sec/Cred' resource.
564  */
565 OCStackResult CreateCredResource()
566 {
567     OCStackResult ret;
568
569     ret = OCCreateResource(&gCredHandle,
570                            OIC_RSRC_TYPE_SEC_CRED,
571                            OIC_MI_DEF,
572                            OIC_RSRC_CRED_URI,
573                            CredEntityHandler,
574                            NULL,
575                            OC_RES_PROP_NONE);
576
577     if (OC_STACK_OK != ret)
578     {
579         OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource"));
580         DeInitCredResource();
581     }
582     return ret;
583 }
584
585 /**
586  * Get the default value
587  * @retval  NULL for now. Update it when we finalize the default info.
588  */
589 static OicSecCred_t* GetCredDefault()
590 {
591     return NULL;
592 }
593
594 /**
595  * Initialize Cred resource by loading data from persistent storage.
596  *
597  * @retval
598  *     OC_STACK_OK    - no errors
599  *     OC_STACK_ERROR - stack process error
600  */
601 OCStackResult InitCredResource()
602 {
603     OCStackResult ret = OC_STACK_ERROR;
604
605     //Read Cred resource from PS
606     char* jsonSVRDatabase = GetSVRDatabase();
607
608     if (jsonSVRDatabase)
609     {
610         //Convert JSON Cred into binary format
611         gCred = JSONToCredBin(jsonSVRDatabase);
612     }
613     /*
614      * If SVR database in persistent storage got corrupted or
615      * is not available for some reason, a default Cred is created
616      * which allows user to initiate Cred provisioning again.
617      */
618     if (!jsonSVRDatabase || !gCred)
619     {
620         gCred = GetCredDefault();
621     }
622     //Instantiate 'oic.sec.cred'
623     ret = CreateCredResource();
624     OICFree(jsonSVRDatabase);
625     return ret;
626 }
627
628 /**
629  * Perform cleanup for Cred resources.
630  *
631  * @return
632  *     OC_STACK_OK              - no errors
633  *     OC_STACK_ERROR           - stack process error
634  *     OC_STACK_NO_RESOURCE     - resource not found
635  *     OC_STACK_INVALID_PARAM   - invalid param
636  */
637 OCStackResult DeInitCredResource()
638 {
639     OCStackResult result = OCDeleteResource(gCredHandle);
640     DeleteCredList(gCred);
641     gCred = NULL;
642     return result;
643 }
644
645 /**
646  * This method is used by tinydtls/SRM to retrieve credential for given Subject.
647  *
648  * @param subject - subject for which credential is required.
649  *
650  * @retval
651  *     reference to OicSecCred_t - if credential is found
652  *     NULL                      - if credential not found
653  */
654 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
655 {
656     OicSecCred_t *cred = NULL;
657
658     if ( NULL == subject)
659     {
660         return NULL;
661     }
662
663     LL_FOREACH(gCred, cred)
664     {
665         if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
666         {
667              return cred;
668         }
669     }
670     return NULL;
671 }
672
673
674 #if defined(__WITH_DTLS__)
675 /**
676  * This internal callback is used by lower stack (i.e. CA layer) to
677  * retrieve PSK credentials from RI security layer.
678  *
679  * Note: When finished, caller should initialize memory to zeros and
680  * invoke OICFree to delete @p credInfo.
681  *
682  * @param credInfo
683  *     binary blob containing PSK credentials
684  *
685  * @retval none
686  */
687 void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo)
688 {
689     CADtlsPskCredsBlob_t * caBlob = NULL;
690     if(credInfo)
691     {
692         caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1);
693         if (caBlob)
694         {
695             OicUuid_t deviceID = {};
696
697             // Retrieve Device ID from doxm resource and copy in PSK creds blob
698             VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR);
699             memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity));
700
701             OicSecCred_t *cred = NULL;
702             size_t count = 0;
703             LL_FOREACH(gCred, cred)
704             {
705                 // Currently, Iotivity supports only symmetric pair wise key credentials
706                 if (cred->credType == SYMMETRIC_PAIR_WISE_KEY)
707                 {
708                     ++count;
709                 }
710             }
711             caBlob->num = count;
712             if (caBlob->num)
713             {
714                 caBlob->creds =
715                     (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds));
716                 VERIFY_NON_NULL(TAG, caBlob->creds, ERROR);
717
718                 unsigned int i = 0;
719                 LL_FOREACH(gCred, cred)
720                 {
721                     if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) &&
722                             (i < count))
723
724                     {
725                         // Copy subject ID
726                         memcpy(caBlob->creds[i].id, cred->subject.id,
727                                 sizeof(caBlob->creds[i].id));
728
729                         // Convert PSK from JSON to binary before copying
730                         uint32_t outLen = 0;
731                         B64Result b64Ret = b64Decode(cred->privateData.data,
732                                 strlen(cred->privateData.data), caBlob->creds[i].psk,
733                                 sizeof(caBlob->creds[i].psk), &outLen);
734                         VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
735                         i++;
736                     }
737                 }
738             }
739         }
740         *credInfo = caBlob;
741         // Return from here after making the credential list
742         return;
743     }
744
745 exit:
746     if (caBlob)
747     {
748         memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds));
749         OICFree(caBlob->creds);
750     }
751     OICFree(caBlob);
752 }
753 #endif /* __WITH_DTLS__ */