1 //******************************************************************
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #define __STDC_LIMIT_MACROS
24 #include "oic_malloc.h"
26 #include "resourcemanager.h"
27 #include "psinterface.h"
29 #include "srmresourcestrings.h"
30 #include "credresource.h"
32 #include "doxmresource.h"
34 #include "srmutility.h"
35 #include "cainterface.h"
44 #define TAG PCF("SRM-CREDL")
47 static OicSecCred_t *gCred = NULL;
48 static OCResourceHandle gCredHandle = NULL;
51 * This function frees OicSecCred_t object's fields and object itself.
53 static void FreeCred(OicSecCred_t *cred)
57 OC_LOG (INFO, TAG, PCF("Invalid Parameter"));
60 //Note: Need further clarification on roleID data type
63 OICFree(cred->roleIds);
67 OICFree(cred->publicData.data);
70 OICFree(cred->privateData.data);
73 OICFree(cred->period);
76 OICFree(cred->owners);
78 //Clean Cred node itself
82 void DeleteCredList(OicSecCred_t* cred)
86 OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
87 LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
89 LL_DELETE(cred, credTmp1);
96 * This function converts credential data into JSON format.
97 * Caller needs to invoke 'free' when done using
99 * @param cred pointer to instance of OicSecCred_t structure.
102 * pointer to JSON credential representation - if credential for subjectId found
103 * NULL - if credential for subjectId not found
105 char * BinToCredJSON(const OicSecCred_t * cred)
107 cJSON *jsonRoot = NULL;
108 char *jsonStr = NULL;
112 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
114 B64Result b64Ret = B64_OK;
116 jsonRoot = cJSON_CreateObject();
117 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
119 cJSON *jsonCredArray = NULL;
120 cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
121 jsonCredArray = cJSON_CreateArray());
122 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
126 cJSON *jsonCred = cJSON_CreateObject();
127 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
129 //CredID -- Mandatory
130 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
132 //Subject -- Mandatory
134 memset(base64Buff, 0, sizeof(base64Buff));
135 b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
136 sizeof(base64Buff), &outLen);
137 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
138 cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
140 //Note: Need further clarification on roleID data type
142 //RoleId -- Not Mandatory
143 if(cred->roleIdsLen > 0)
145 cJSON *jsonRoleIdsArray = NULL;
146 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
147 jsonRoleIdsArray = cJSON_CreateArray());
148 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
149 for (size_t i = 0; i < cred->roleIdsLen; i++)
151 cJSON_AddItemToArray (jsonRoleIdsArray,
152 cJSON_CreateString((char *)cred->roleIds[i].id));
157 //CredType -- Mandatory
158 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
161 //PublicData -- Not Mandatory
162 if(cred->publicData.data)
164 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
167 //PrivateData -- Not Mandatory
168 if(cred->privateData.data)
170 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
173 //Period -- Not Mandatory
176 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
180 //Owners -- Mandatory
181 cJSON *jsonOwnrArray = NULL;
182 cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
183 jsonOwnrArray = cJSON_CreateArray());
184 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
185 for (size_t i = 0; i < cred->ownersLen; i++)
188 memset(base64Buff, 0, sizeof(base64Buff));
189 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
190 base64Buff, sizeof(base64Buff), &outLen);
191 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
192 cJSON_AddItemToArray (jsonOwnrArray,
193 cJSON_CreateString((char *)(base64Buff)));
196 /* Attach current cred node to cred Array */
197 cJSON_AddItemToArray(jsonCredArray, jsonCred);
201 jsonStr = cJSON_PrintUnformatted(jsonRoot);
207 cJSON_Delete(jsonRoot);
213 * This internal method converts JSON cred into binary cred.
215 OicSecCred_t * JSONToCredBin(const char * jsonStr)
217 OCStackResult ret = OC_STACK_ERROR;
218 OicSecCred_t * headCred = NULL;
219 OicSecCred_t * prevCred = NULL;
220 cJSON *jsonCredArray = NULL;
222 cJSON *jsonRoot = cJSON_Parse(jsonStr);
223 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
225 jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
226 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
227 if (cJSON_Array == jsonCredArray->type)
229 int numCred = cJSON_GetArraySize(jsonCredArray);
232 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
234 B64Result b64Ret = B64_OK;
236 VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
239 cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
240 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
242 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
243 VERIFY_NON_NULL(TAG, cred, ERROR);
245 headCred = (headCred) ? headCred : cred;
248 prevCred->next = cred;
250 size_t jsonObjLen = 0;
251 cJSON *jsonObj = NULL;
253 //CredId -- Mandatory
254 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
257 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
258 cred->credId = jsonObj->valueint;
261 //subject -- Mandatory
262 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
263 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
264 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
266 memset(base64Buff, 0, sizeof(base64Buff));
267 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
268 base64Buff, sizeof(base64Buff), &outLen);
269 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
271 memcpy(cred->subject.id, base64Buff, outLen);
273 //CredType -- Mandatory
274 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
275 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
276 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
277 cred->credType = jsonObj->valueint;
279 //PrivateData is mandatory for some of the credential types listed below.
280 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
281 if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
282 (cred->credType & SYMMETRIC_GROUP_KEY) ||
283 (cred->credType & PIN_PASSWORD))
285 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
286 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
288 if(jsonObj && cJSON_String == jsonObj->type)
290 jsonObjLen = strlen(jsonObj->valuestring) + 1;
291 cred->privateData.data = (char *)OICMalloc(jsonObjLen);
292 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
293 strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
296 //Period -- Not Mandatory
297 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
298 if(jsonObj && cJSON_String == jsonObj->type)
300 jsonObjLen = strlen(jsonObj->valuestring) + 1;
301 cred->period = (char *)OICMalloc(jsonObjLen);
302 VERIFY_NON_NULL(TAG, cred->period, ERROR);
303 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
306 //Owners -- Mandatory
307 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
308 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
309 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR)
310 cred->ownersLen = cJSON_GetArraySize(jsonObj);
311 VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
312 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
313 VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
314 for(size_t i = 0; i < cred->ownersLen; i++)
316 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
317 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
318 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
320 memset(base64Buff, 0, sizeof(base64Buff));
321 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
322 base64Buff, sizeof(base64Buff), &outLen);
323 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
324 outLen <= sizeof(cred->owners[i].id)), ERROR);
325 memcpy(cred->owners[i].id, base64Buff, outLen);
328 } while( ++idx < numCred);
334 cJSON_Delete(jsonRoot);
335 if (OC_STACK_OK != ret)
337 DeleteCredList(headCred);
344 * This function generates the bin credential data.
346 * @param subject pointer to subject of this credential.
347 * @param credType credential type.
348 * @param publicData public data such as public key.
349 * @param privateData private data such as private key.
350 * The privateData is expected in base64 encoded format.
351 * @param ownersLen length of owners array
352 * @param owners array of owners.
355 * pointer to instance of OicSecCred_t - success
358 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
359 const char * publicData, const char * privateData,
360 size_t ownersLen, const OicUuid_t * owners)
363 OCStackResult ret = OC_STACK_ERROR;
365 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
366 VERIFY_NON_NULL(TAG, cred, ERROR);
368 //CredId is assigned before appending new cred to the existing
369 //credential list and updating svr database in AddCredential().
372 VERIFY_NON_NULL(TAG, subject, ERROR);
373 memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
375 VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
376 SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
377 cred->credType = credType;
382 cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
383 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
384 strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
390 cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
391 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
392 strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
395 VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
396 cred->ownersLen = ownersLen;
398 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
399 VERIFY_NON_NULL(TAG, cred->owners, ERROR);
400 for(size_t i = 0; i < cred->ownersLen; i++)
402 memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
407 if (OC_STACK_OK != ret)
409 DeleteCredList(cred);
415 static bool UpdatePersistentStorage(const OicSecCred_t *cred)
419 // Convert Cred data into JSON for update to persistent storage
420 char *jsonStr = BinToCredJSON(cred);
423 cJSON *jsonCred = cJSON_Parse(jsonStr);
427 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
431 cJSON_Delete(jsonCred );
433 else //Empty cred list
435 if (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, NULL))
444 * Compare function used LL_SORT for sorting credentials
446 * @param first pointer to OicSecCred_t struct
447 * @param second pointer to OicSecCred_t struct
450 * -1 if credId of first is less than credId of second
451 * 0 if credId of first is equal to credId of second
452 * 1 if credId of first is greater than credId of second
454 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
456 if(first->credId < second->credId)
460 else if(first->credId > second->credId)
469 * GetCredId goes through the cred list and returns the next
470 * available credId. The next credId could be the credId that is
471 * available due deletion of OicSecCred_t object or one more than
472 * credId of last credential in the list.
475 * next available credId - success
479 static uint16_t GetCredId()
481 //Sorts credential list in incremental order of credId
482 LL_SORT(gCred, CmpCredId);
485 OicSecCred_t *currentCred = NULL, *credTmp = NULL;
486 uint16_t nextCredId = 1;
488 LL_FOREACH_SAFE(gCred, currentCred, credTmp)
490 if(currentCred->credId == nextCredId)
500 VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
509 * This function adds the new cred to the credential list.
511 * @param cred pointer to new credential.
514 * OC_STACK_OK - cred not NULL and persistent storage gets updated
515 * OC_STACK_ERROR - cred is NULL or fails to update persistent storage
517 OCStackResult AddCredential(OicSecCred_t * newCred)
519 OCStackResult ret = OC_STACK_ERROR;
521 VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
523 //Assigning credId to the newCred
524 newCred->credId = GetCredId();
526 VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
528 //Append the new Cred to existing list
529 LL_APPEND(gCred, newCred);
531 if(UpdatePersistentStorage(gCred))
540 OCStackResult RemoveCredential(const OicUuid_t *subject)
542 OCStackResult ret = OC_STACK_ERROR;
543 OicSecCred_t *cred = NULL;
544 OicSecCred_t *tempCred = NULL;
545 bool deleteFlag = false;
547 LL_FOREACH_SAFE(gCred, cred, tempCred)
549 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
551 LL_DELETE(gCred, cred);
559 if(UpdatePersistentStorage(gCred))
561 ret = OC_STACK_RESOURCE_DELETED;
568 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
570 OCEntityHandlerResult ret = OC_EH_ERROR;
572 //Get binary representation of json
573 OicSecCred_t * cred = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
577 //If the Post request credential has credId, it will be
578 //discarded and the next available credId will be assigned
579 //to it before getting appended to the existing credential
580 //list and updating svr database.
581 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
587 static OCEntityHandlerResult HandleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
589 OC_LOG_V (INFO, TAG, PCF("Processing CredDeleteRequest"));
591 OCEntityHandlerResult ehRet = OC_EH_ERROR;
593 if(NULL == ehRequest->query)
598 OicParseQueryIter_t parseIter = {.attrPos=NULL};
599 OicUuid_t subject = {.id={0}};
601 //Parsing REST query to get the subject
602 ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
603 while(GetNextQuery(&parseIter))
605 if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME,
606 parseIter.attrLen) == 0)
608 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
610 B64Result b64Ret = B64_OK;
612 b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen,
613 base64Buff, sizeof(base64Buff), &outLen);
615 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
616 memcpy(subject.id, base64Buff, outLen);
620 if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&subject))
622 ehRet = OC_EH_RESOURCE_DELETED;
631 * This internal method is the entity handler for Cred resources
632 * to handle REST request (PUT/POST/DEL)
634 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
635 OCEntityHandlerRequest * ehRequest,
636 void* callbackParameter)
638 (void)callbackParameter;
639 OCEntityHandlerResult ret = OC_EH_ERROR;
645 if (flag & OC_REQUEST_FLAG)
647 OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
648 //TODO : Handle PUT/DEL methods
649 switch(ehRequest->method)
652 ret = OC_EH_FORBIDDEN;
655 ret = HandlePostRequest(ehRequest);
658 ret = HandleDeleteRequest(ehRequest);
666 //Send payload to request originator
667 ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
674 * This internal method is used to create '/oic/sec/Cred' resource.
676 OCStackResult CreateCredResource()
680 ret = OCCreateResource(&gCredHandle,
681 OIC_RSRC_TYPE_SEC_CRED,
688 if (OC_STACK_OK != ret)
690 OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource"));
691 DeInitCredResource();
697 * Get the default value
698 * @retval NULL for now. Update it when we finalize the default info.
700 static OicSecCred_t* GetCredDefault()
706 * Initialize Cred resource by loading data from persistent storage.
709 * OC_STACK_OK - no errors
710 * OC_STACK_ERROR - stack process error
712 OCStackResult InitCredResource()
714 OCStackResult ret = OC_STACK_ERROR;
716 //Read Cred resource from PS
717 char* jsonSVRDatabase = GetSVRDatabase();
721 //Convert JSON Cred into binary format
722 gCred = JSONToCredBin(jsonSVRDatabase);
725 * If SVR database in persistent storage got corrupted or
726 * is not available for some reason, a default Cred is created
727 * which allows user to initiate Cred provisioning again.
729 if (!jsonSVRDatabase || !gCred)
731 gCred = GetCredDefault();
733 //Instantiate 'oic.sec.cred'
734 ret = CreateCredResource();
735 OICFree(jsonSVRDatabase);
740 * Perform cleanup for Cred resources.
743 * OC_STACK_OK - no errors
744 * OC_STACK_ERROR - stack process error
745 * OC_STACK_NO_RESOURCE - resource not found
746 * OC_STACK_INVALID_PARAM - invalid param
748 OCStackResult DeInitCredResource()
750 OCStackResult result = OCDeleteResource(gCredHandle);
751 DeleteCredList(gCred);
757 * This method is used by tinydtls/SRM to retrieve credential for given Subject.
759 * @param subject - subject for which credential is required.
762 * reference to OicSecCred_t - if credential is found
763 * NULL - if credential not found
765 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
767 OicSecCred_t *cred = NULL;
769 if ( NULL == subject)
774 LL_FOREACH(gCred, cred)
776 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
785 #if defined(__WITH_DTLS__)
787 * This internal callback is used by lower stack (i.e. CA layer) to
788 * retrieve PSK credentials from RI security layer.
790 * Note: When finished, caller should initialize memory to zeros and
791 * invoke OICFree to delete @p credInfo.
794 * binary blob containing PSK credentials
798 void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo)
800 CADtlsPskCredsBlob_t * caBlob = NULL;
803 caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1);
806 OicUuid_t deviceID = {.id={}};
808 // Retrieve Device ID from doxm resource and copy in PSK creds blob
809 VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR);
810 memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity));
812 OicSecCred_t *cred = NULL;
814 LL_FOREACH(gCred, cred)
816 // Currently, Iotivity supports only symmetric pair wise key credentials
817 if (cred->credType == SYMMETRIC_PAIR_WISE_KEY)
826 (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds));
827 VERIFY_NON_NULL(TAG, caBlob->creds, ERROR);
830 LL_FOREACH(gCred, cred)
832 if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) &&
837 memcpy(caBlob->creds[i].id, cred->subject.id,
838 sizeof(caBlob->creds[i].id));
840 // Convert PSK from JSON to binary before copying
842 B64Result b64Ret = b64Decode(cred->privateData.data,
843 strlen(cred->privateData.data), caBlob->creds[i].psk,
844 sizeof(caBlob->creds[i].psk), &outLen);
845 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
852 // Return from here after making the credential list
859 memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds));
860 OICFree(caBlob->creds);
864 #endif /* __WITH_DTLS__ */