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