Merging security-M3 to 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 #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 {
452     OCEntityHandlerResult ret = OC_EH_ERROR;
453
454     if(!ehRequest)
455     {
456         return OC_EH_ERROR;
457     }
458     if (flag & OC_REQUEST_FLAG)
459     {
460         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
461         //TODO :  Handle PUT/DEL methods
462         switch(ehRequest->method)
463         {
464             case OC_REST_GET:
465                 ret = OC_EH_FORBIDDEN;
466                 break;
467             case OC_REST_POST:
468                 ret = HandlePostRequest(ehRequest);
469                 break;
470             default:
471                 ret = OC_EH_ERROR;
472                 break;
473         }
474     }
475
476     //Send payload to request originator
477     ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
478                        ret : OC_EH_ERROR);
479
480     return ret;
481 }
482
483 /*
484  * This internal method is used to create '/oic/sec/Cred' resource.
485  */
486 OCStackResult CreateCredResource()
487 {
488     OCStackResult ret;
489
490     ret = OCCreateResource(&gCredHandle,
491                            OIC_RSRC_TYPE_SEC_CRED,
492                            OIC_MI_DEF,
493                            OIC_RSRC_CRED_URI,
494                            CredEntityHandler,
495                            OC_RES_PROP_NONE);
496
497     if (OC_STACK_OK != ret)
498     {
499         OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource"));
500         DeInitCredResource();
501     }
502     return ret;
503 }
504
505 /**
506  * Get the default value
507  * @retval  NULL for now. Update it when we finalize the default info.
508  */
509 static OicSecCred_t* GetCredDefault()
510 {
511     return NULL;
512 }
513
514 /**
515  * Initialize Cred resource by loading data from persistent storage.
516  *
517  * @retval
518  *     OC_STACK_OK    - no errors
519  *     OC_STACK_ERROR - stack process error
520  */
521 OCStackResult InitCredResource()
522 {
523     OCStackResult ret = OC_STACK_ERROR;
524
525     //Read Cred resource from PS
526     char* jsonSVRDatabase = GetSVRDatabase();
527
528     if (jsonSVRDatabase)
529     {
530         //Convert JSON Cred into binary format
531         gCred = JSONToCredBin(jsonSVRDatabase);
532     }
533     /*
534      * If SVR database in persistent storage got corrupted or
535      * is not available for some reason, a default Cred is created
536      * which allows user to initiate Cred provisioning again.
537      */
538     if (!jsonSVRDatabase || !gCred)
539     {
540         gCred = GetCredDefault();
541     }
542     //Instantiate 'oic.sec.cred'
543     ret = CreateCredResource();
544     OICFree(jsonSVRDatabase);
545     return ret;
546 }
547
548 /**
549  * Perform cleanup for Cred resources.
550  *
551  * @return
552  *     OC_STACK_OK              - no errors
553  *     OC_STACK_ERROR           - stack process error
554  *     OC_STACK_NO_RESOURCE     - resource not found
555  *     OC_STACK_INVALID_PARAM   - invalid param
556  */
557 OCStackResult DeInitCredResource()
558 {
559     OCStackResult result = OCDeleteResource(gCredHandle);
560     DeleteCredList(gCred);
561     gCred = NULL;
562     return result;
563 }
564
565 /**
566  * This method is used by tinydtls/SRM to retrieve credential for given Subject.
567  *
568  * @param subject - subject for which credential is required.
569  *
570  * @retval
571  *     reference to OicSecCred_t - if credential is found
572  *     NULL                      - if credential not found
573  */
574 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
575 {
576     OicSecCred_t *cred = NULL;
577
578     if ( NULL == subject)
579     {
580         return NULL;
581     }
582
583     LL_FOREACH(gCred, cred)
584     {
585         if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
586         {
587              return cred;
588         }
589     }
590     return NULL;
591 }
592
593
594 #if defined(__WITH_DTLS__)
595 /**
596  * This internal callback is used by lower stack (i.e. CA layer) to
597  * retrieve PSK credentials from RI security layer.
598  *
599  * Note: When finished, caller should initialize memory to zeros and
600  * invoke OICFree to delete @p credInfo.
601  *
602  * @param credInfo
603  *     binary blob containing PSK credentials
604  *
605  * @retval none
606  */
607 void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo)
608 {
609     CADtlsPskCredsBlob_t * caBlob = NULL;
610     if(credInfo)
611     {
612         caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1);
613         if (caBlob)
614         {
615             OicUuid_t deviceID = {};
616
617             // Retrieve Device ID from doxm resource and copy in PSK creds blob
618             VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR);
619             memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity));
620
621             OicSecCred_t *cred = NULL;
622             size_t count = 0;
623             LL_FOREACH(gCred, cred)
624             {
625                 // Currently, Iotivity supports only symmetric pair wise key credentials
626                 if (cred->credType == SYMMETRIC_PAIR_WISE_KEY)
627                 {
628                     ++count;
629                 }
630             }
631             caBlob->num = count;
632             if (caBlob->num)
633             {
634                 caBlob->creds =
635                     (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds));
636                 VERIFY_NON_NULL(TAG, caBlob->creds, ERROR);
637
638                 unsigned int i = 0;
639                 LL_FOREACH(gCred, cred)
640                 {
641                     if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) &&
642                             (i < count))
643
644                     {
645                         // Copy subject ID
646                         memcpy(caBlob->creds[i].id, cred->subject.id,
647                                 sizeof(caBlob->creds[i].id));
648
649                         // Convert PSK from JSON to binary before copying
650                         uint32_t outLen = 0;
651                         B64Result b64Ret = b64Decode(cred->privateData.data,
652                                 strlen(cred->privateData.data), caBlob->creds[i].psk,
653                                 sizeof(caBlob->creds[i].psk), &outLen);
654                         VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
655                         i++;
656                     }
657                 }
658             }
659         }
660         *credInfo = caBlob;
661         // Return from here after making the credential list
662         return;
663     }
664
665 exit:
666     if (caBlob)
667     {
668         memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds));
669         OICFree(caBlob->creds);
670     }
671     OICFree(caBlob);
672 }
673 #endif /* __WITH_DTLS__ */