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"
38 #include "iotvticalendar.h"
39 #include "ocserverrequest.h"
43 #endif //__WITH_DTLS__
52 #define TAG "SRM-CREDL"
55 static OicSecCred_t *gCred = NULL;
56 static OCResourceHandle gCredHandle = NULL;
59 * This function frees OicSecCred_t object's fields and object itself.
61 static void FreeCred(OicSecCred_t *cred)
65 OIC_LOG (ERROR, TAG, "Invalid Parameter");
68 //Note: Need further clarification on roleID data type
71 OICFree(cred->roleIds);
75 OICFree(cred->publicData.data);
78 OICFree(cred->privateData.data);
81 OICFree(cred->period);
84 OICFree(cred->owners);
86 //Clean Cred node itself
90 void DeleteCredList(OicSecCred_t* cred)
94 OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
95 LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
97 LL_DELETE(cred, credTmp1);
104 * This function converts credential data into JSON format.
105 * Caller needs to invoke 'free' when done using
107 * @param cred pointer to instance of OicSecCred_t structure.
110 * pointer to JSON credential representation - if credential for subjectId found
111 * NULL - if credential for subjectId not found
113 char * BinToCredJSON(const OicSecCred_t * cred)
115 cJSON *jsonRoot = NULL;
116 char *jsonStr = NULL;
120 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
122 B64Result b64Ret = B64_OK;
124 jsonRoot = cJSON_CreateObject();
125 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
127 cJSON *jsonCredArray = NULL;
128 cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
129 jsonCredArray = cJSON_CreateArray());
130 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
134 cJSON *jsonCred = cJSON_CreateObject();
135 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
137 //CredID -- Mandatory
138 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
140 //Subject -- Mandatory
142 memset(base64Buff, 0, sizeof(base64Buff));
143 b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
144 sizeof(base64Buff), &outLen);
145 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
146 cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
148 //Note: Need further clarification on roleID data type
150 //RoleId -- Not Mandatory
151 if(cred->roleIdsLen > 0)
153 cJSON *jsonRoleIdsArray = NULL;
154 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
155 jsonRoleIdsArray = cJSON_CreateArray());
156 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
157 for (size_t i = 0; i < cred->roleIdsLen; i++)
159 cJSON_AddItemToArray (jsonRoleIdsArray,
160 cJSON_CreateString((char *)cred->roleIds[i].id));
165 //CredType -- Mandatory
166 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
169 //PublicData -- Not Mandatory
170 if(cred->publicData.data)
172 if (SIGNED_ASYMMETRIC_KEY == cred->credType)
174 cJSON_AddItemToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME,
175 cJSON_Parse(cred->publicData.data));
179 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
182 #endif /*__WITH_X509__*/
183 //PrivateData -- Not Mandatory
184 if(cred->privateData.data)
187 if (SIGNED_ASYMMETRIC_KEY == cred->credType)
189 cJSON_AddItemToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME,
190 cJSON_Parse(cred->privateData.data));
194 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
197 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
201 //Period -- Not Mandatory
204 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
208 //Owners -- Mandatory
209 cJSON *jsonOwnrArray = NULL;
210 cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
211 jsonOwnrArray = cJSON_CreateArray());
212 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
213 for (size_t i = 0; i < cred->ownersLen; i++)
216 memset(base64Buff, 0, sizeof(base64Buff));
217 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
218 base64Buff, sizeof(base64Buff), &outLen);
219 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
220 cJSON_AddItemToArray (jsonOwnrArray,
221 cJSON_CreateString((char *)(base64Buff)));
224 /* Attach current cred node to cred Array */
225 cJSON_AddItemToArray(jsonCredArray, jsonCred);
229 jsonStr = cJSON_PrintUnformatted(jsonRoot);
235 cJSON_Delete(jsonRoot);
241 * This internal method converts JSON cred into binary cred.
243 OicSecCred_t * JSONToCredBin(const char * jsonStr)
245 OCStackResult ret = OC_STACK_ERROR;
246 OicSecCred_t * headCred = NULL;
247 OicSecCred_t * prevCred = NULL;
248 cJSON *jsonCredArray = NULL;
250 cJSON *jsonRoot = cJSON_Parse(jsonStr);
251 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
253 jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
254 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
255 if (cJSON_Array == jsonCredArray->type)
257 int numCred = cJSON_GetArraySize(jsonCredArray);
260 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
262 B64Result b64Ret = B64_OK;
264 VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
267 cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
268 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
270 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
271 VERIFY_NON_NULL(TAG, cred, ERROR);
273 headCred = (headCred) ? headCred : cred;
276 prevCred->next = cred;
278 size_t jsonObjLen = 0;
279 cJSON *jsonObj = NULL;
281 //CredId -- Mandatory
282 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
285 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
286 cred->credId = jsonObj->valueint;
289 //subject -- Mandatory
290 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
291 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
292 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
294 memset(base64Buff, 0, sizeof(base64Buff));
295 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
296 base64Buff, sizeof(base64Buff), &outLen);
297 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
299 memcpy(cred->subject.id, base64Buff, outLen);
301 //CredType -- Mandatory
302 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
303 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
304 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
305 cred->credType = (OicSecCredType_t)jsonObj->valueint;
307 //PrivateData is mandatory for some of the credential types listed below.
308 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
309 if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
310 (cred->credType & SYMMETRIC_GROUP_KEY) ||
311 (cred->credType & PIN_PASSWORD))
315 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
319 else if (cred->credType & SIGNED_ASYMMETRIC_KEY)
321 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
322 VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
324 #endif // __WITH_X509__
327 if (cJSON_String == jsonObj->type)
329 jsonObjLen = strlen(jsonObj->valuestring) + 1;
330 cred->privateData.data = (char *)OICMalloc(jsonObjLen);
331 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
332 strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
335 else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
337 cred->privateData.data = cJSON_PrintUnformatted(jsonObj);
338 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
340 #endif // __WITH_X509__
344 cred->privateData.data = NULL;
347 //PublicData is mandatory only for SIGNED_ASYMMETRIC_KEY credentials type.
348 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PUBLICDATA_NAME);
350 if (cred->credType & SIGNED_ASYMMETRIC_KEY)
352 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
353 VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
355 #endif // __WITH_X509__
358 if (cJSON_String == jsonObj->type)
360 jsonObjLen = strlen(jsonObj->valuestring) + 1;
361 cred->publicData.data = (char *)OICMalloc(jsonObjLen);
362 VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
363 strncpy((char *)cred->publicData.data, (char *)jsonObj->valuestring, jsonObjLen);
366 else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
368 cred->publicData.data = cJSON_PrintUnformatted(jsonObj);
369 VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
371 #endif // __WITH_X509__
374 //Period -- Not Mandatory
375 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
376 if(jsonObj && cJSON_String == jsonObj->type)
378 jsonObjLen = strlen(jsonObj->valuestring) + 1;
379 cred->period = (char *)OICMalloc(jsonObjLen);
380 VERIFY_NON_NULL(TAG, cred->period, ERROR);
381 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
384 //Owners -- Mandatory
385 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
386 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
387 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
388 cred->ownersLen = (size_t)cJSON_GetArraySize(jsonObj);
389 VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
390 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
391 VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
392 for(size_t i = 0; i < cred->ownersLen; i++)
394 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
395 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
396 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
398 memset(base64Buff, 0, sizeof(base64Buff));
399 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
400 base64Buff, sizeof(base64Buff), &outLen);
401 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
402 outLen <= sizeof(cred->owners[i].id)), ERROR);
403 memcpy(cred->owners[i].id, base64Buff, outLen);
406 } while( ++idx < numCred);
412 cJSON_Delete(jsonRoot);
413 if (OC_STACK_OK != ret)
415 DeleteCredList(headCred);
422 * This function generates the bin credential data.
424 * @param subject pointer to subject of this credential.
425 * @param credType credential type.
426 * @param publicData public data such as public key.
427 * @param privateData private data such as private key.
428 * The privateData is expected in base64 encoded format.
429 * @param ownersLen length of owners array
430 * @param owners array of owners.
433 * pointer to instance of OicSecCred_t - success
436 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
437 const char * publicData, const char * privateData,
438 size_t ownersLen, const OicUuid_t * owners)
441 OCStackResult ret = OC_STACK_ERROR;
443 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
444 VERIFY_NON_NULL(TAG, cred, ERROR);
446 //CredId is assigned before appending new cred to the existing
447 //credential list and updating svr database in AddCredential().
450 VERIFY_NON_NULL(TAG, subject, ERROR);
451 memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
453 VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
454 SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
455 cred->credType = credType;
460 cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
461 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
462 strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
464 #endif // __WITH_X509__
468 cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
469 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
470 strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
473 VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
474 cred->ownersLen = ownersLen;
476 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
477 VERIFY_NON_NULL(TAG, cred->owners, ERROR);
478 for(size_t i = 0; i < cred->ownersLen; i++)
480 memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
485 if (OC_STACK_OK != ret)
487 DeleteCredList(cred);
493 static bool UpdatePersistentStorage(const OicSecCred_t *cred)
497 // Convert Cred data into JSON for update to persistent storage
498 char *jsonStr = BinToCredJSON(cred);
501 cJSON *jsonCred = cJSON_Parse(jsonStr);
505 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
509 cJSON_Delete(jsonCred );
511 else //Empty cred list
513 if (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, NULL))
522 * Compare function used LL_SORT for sorting credentials
524 * @param first pointer to OicSecCred_t struct
525 * @param second pointer to OicSecCred_t struct
528 * -1 if credId of first is less than credId of second
529 * 0 if credId of first is equal to credId of second
530 * 1 if credId of first is greater than credId of second
532 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
534 if(first->credId < second->credId)
538 else if(first->credId > second->credId)
547 * GetCredId goes through the cred list and returns the next
548 * available credId. The next credId could be the credId that is
549 * available due deletion of OicSecCred_t object or one more than
550 * credId of last credential in the list.
553 * next available credId - success
557 static uint16_t GetCredId()
559 //Sorts credential list in incremental order of credId
560 LL_SORT(gCred, CmpCredId);
563 OicSecCred_t *currentCred = NULL, *credTmp = NULL;
564 uint16_t nextCredId = 1;
566 LL_FOREACH_SAFE(gCred, currentCred, credTmp)
568 if(currentCred->credId == nextCredId)
578 VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
586 * Get the default value
587 * @retval NULL for now. Update it when we finalize the default info.
589 static OicSecCred_t* GetCredDefault()
595 * This function adds the new cred to the credential list.
597 * @param cred pointer to new credential.
600 * OC_STACK_OK - cred not NULL and persistent storage gets updated
601 * OC_STACK_ERROR - cred is NULL or fails to update persistent storage
603 OCStackResult AddCredential(OicSecCred_t * newCred)
605 OCStackResult ret = OC_STACK_ERROR;
607 VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
609 //Assigning credId to the newCred
610 newCred->credId = GetCredId();
612 VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
614 //Append the new Cred to existing list
615 LL_APPEND(gCred, newCred);
617 if(UpdatePersistentStorage(gCred))
626 OCStackResult RemoveCredential(const OicUuid_t *subject)
628 OCStackResult ret = OC_STACK_ERROR;
629 OicSecCred_t *cred = NULL;
630 OicSecCred_t *tempCred = NULL;
631 bool deleteFlag = false;
633 LL_FOREACH_SAFE(gCred, cred, tempCred)
635 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
637 LL_DELETE(gCred, cred);
645 if(UpdatePersistentStorage(gCred))
647 ret = OC_STACK_RESOURCE_DELETED;
655 * Remove all credential data on credential resource and persistent storage
658 * OC_STACK_OK - no errors
659 * OC_STACK_ERROR - stack process error
661 OCStackResult RemoveAllCredentials(void)
663 DeleteCredList(gCred);
664 gCred = GetCredDefault();
666 if(!UpdatePersistentStorage(gCred))
668 return OC_STACK_ERROR;
675 * Internal function to fill private data of owner PSK.
677 * @param receviedCred recevied owner credential from OBT(PT)
678 * @param ownerAdd address of OBT(PT)
679 * @param doxm current device's doxm resource
682 * true successfully done and valid ower psk information
683 * false Invalid owner psk information or failed to owner psk generation
685 static bool FillPrivateDataOfOwnerPSK(OicSecCred_t* receviedCred, const CAEndpoint_t* ownerAddr,
686 const OicSecDoxm_t* doxm)
688 //Derive OwnerPSK locally
689 const char* oxmLabel = GetOxmString(doxm->oxmSel);
690 VERIFY_NON_NULL(TAG, oxmLabel, ERROR);
692 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
693 CAResult_t pskRet = CAGenerateOwnerPSK(ownerAddr,
694 (uint8_t*)oxmLabel, strlen(oxmLabel),
695 doxm->owner.id, sizeof(doxm->owner.id),
696 doxm->deviceID.id, sizeof(doxm->deviceID.id),
697 ownerPSK, OWNER_PSK_LENGTH_128);
698 VERIFY_SUCCESS(TAG, pskRet == CA_STATUS_OK, ERROR);
700 OIC_LOG(DEBUG, TAG, "OwnerPSK dump :");
701 OIC_LOG_BUFFER(DEBUG, TAG, ownerPSK, OWNER_PSK_LENGTH_128);
703 //Generate owner credential based on recevied credential information
704 size_t b64BufSize = B64ENCODE_OUT_SAFESIZE(OWNER_PSK_LENGTH_128 * sizeof(char));
705 uint8_t* encodeBuff = OICMalloc((b64BufSize + 1) * sizeof(char));
706 VERIFY_NON_NULL(TAG, encodeBuff, ERROR);
707 uint32_t encodedSize = 0;
708 B64Result b64Ret = b64Encode(ownerPSK, OWNER_PSK_LENGTH_128,
709 (char*)encodeBuff, b64BufSize + 1, &encodedSize);
710 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
711 encodeBuff[encodedSize] = '\0';
713 //memory re-allocation for private data
714 OICFree(receviedCred->privateData.data);
715 receviedCred->privateData.data = (char*)OICMalloc((encodedSize + 1) * sizeof(char));
716 VERIFY_NON_NULL(TAG, receviedCred->privateData.data, ERROR);
718 //fill the base64 encoded private data
719 strncpy(receviedCred->privateData.data, (char*)encodeBuff, b64BufSize + 1);
721 OIC_LOG(INFO, TAG, "PrivateData of OwnerPSK was calculated successfully");
723 //deallocate local memory
726 //Verify OwnerPSK information
727 return (memcmp(&(receviedCred->subject), &(doxm->owner), sizeof(OicUuid_t)) == 0 &&
728 receviedCred->credType == SYMMETRIC_PAIR_WISE_KEY);
730 //receviedCred->privateData.data will be deallocated when deleting credential.
735 #endif //__WITH_DTLS__
737 static OCEntityHandlerResult HandlePutRequest(const OCEntityHandlerRequest * ehRequest)
739 OCEntityHandlerResult ret = OC_EH_ERROR;
741 //Get binary representation of json
742 OicSecCred_t * cred = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
747 OicUuid_t emptyUuid = {.id={0}};
748 const OicSecDoxm_t* doxm = GetDoxmResourceData();
749 if(false == doxm->owned && memcmp(&(doxm->owner), &emptyUuid, sizeof(OicUuid_t)) != 0)
751 //in case of owner PSK
752 switch(cred->credType)
754 case SYMMETRIC_PAIR_WISE_KEY:
756 OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;
757 if(FillPrivateDataOfOwnerPSK(cred, (CAEndpoint_t *)&request->devAddr, doxm))
759 if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&cred->subject))
761 OIC_LOG(WARNING, TAG, "The credential with the same subject ID was detected!");
764 OIC_LOG(ERROR, TAG, "OwnerPSK was generated successfully.");
765 if(OC_STACK_OK == AddCredential(cred))
767 ret = OC_EH_RESOURCE_CREATED;
771 OIC_LOG(ERROR, TAG, "Failed to save the OwnerPSK as cred resource");
777 OIC_LOG(ERROR, TAG, "Failed to verify receviced OwnerPKS.");
781 if(OC_EH_RESOURCE_CREATED == ret)
784 * in case of random PIN based OxM,
785 * revert get_psk_info callback of tinyDTLS to use owner credential.
787 if(OIC_RANDOM_DEVICE_PIN == doxm->oxmSel)
789 OicUuid_t emptyUuid = { .id={0}};
790 SetUuidForRandomPinOxm(&emptyUuid);
792 if(CA_STATUS_OK != CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials))
794 OIC_LOG(ERROR, TAG, "Failed to revert DTLS credential handler.");
800 //Select cipher suite to use owner PSK
801 if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false))
803 OIC_LOG(ERROR, TAG, "Failed to disable anonymous cipher suite");
808 OIC_LOG(INFO, TAG, "Anonymous cipher suite is DISABLED");
812 CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256))
814 OIC_LOG(ERROR, TAG, "Failed to select cipher suite");
821 case SYMMETRIC_GROUP_KEY:
823 case SIGNED_ASYMMETRIC_KEY:
825 case ASYMMETRIC_ENCRYPTION_KEY:
827 OIC_LOG(WARNING, TAG, "Unsupported credential type for owner credential.");
833 OIC_LOG(WARNING, TAG, "Unknow credential type for owner credential.");
839 if(OC_EH_RESOURCE_CREATED != ret)
842 * If some error is occured while ownership transfer,
843 * ownership transfer related resource should be revert back to initial status.
845 RestoreDoxmToInitState();
846 RestorePstatToInitState();
852 * If the post request credential has credId, it will be
853 * discarded and the next available credId will be assigned
854 * to it before getting appended to the existing credential
855 * list and updating svr database.
857 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
859 #else //not __WITH_DTLS__
861 * If the post request credential has credId, it will be
862 * discarded and the next available credId will be assigned
863 * to it before getting appended to the existing credential
864 * list and updating svr database.
866 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
867 #endif//__WITH_DTLS__
870 if(OC_EH_RESOURCE_CREATED != ret)
872 if(OC_STACK_OK != RemoveCredential(&cred->subject))
874 OIC_LOG(WARNING, TAG, "Failed to remove the invalid credential");
882 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
884 OCEntityHandlerResult ret = OC_EH_ERROR;
886 //Get binary representation of json
887 OicSecCred_t * cred = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
891 //If the Post request credential has credId, it will be
892 //discarded and the next available credId will be assigned
893 //to it before getting appended to the existing credential
894 //list and updating svr database.
895 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
901 static OCEntityHandlerResult HandleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
903 OIC_LOG(DEBUG, TAG, "Processing CredDeleteRequest");
905 OCEntityHandlerResult ehRet = OC_EH_ERROR;
907 if(NULL == ehRequest->query)
912 OicParseQueryIter_t parseIter = {.attrPos=NULL};
913 OicUuid_t subject = {.id={0}};
915 //Parsing REST query to get the subject
916 ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
917 while(GetNextQuery(&parseIter))
919 if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME,
920 parseIter.attrLen) == 0)
922 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
924 B64Result b64Ret = B64_OK;
926 b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen,
927 base64Buff, sizeof(base64Buff), &outLen);
929 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
930 memcpy(subject.id, base64Buff, outLen);
934 if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&subject))
936 ehRet = OC_EH_RESOURCE_DELETED;
944 * This internal method is the entity handler for Cred resources
945 * to handle REST request (PUT/POST/DEL)
947 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
948 OCEntityHandlerRequest * ehRequest,
949 void* callbackParameter)
951 (void)callbackParameter;
952 OCEntityHandlerResult ret = OC_EH_ERROR;
958 if (flag & OC_REQUEST_FLAG)
960 OIC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
961 //TODO : Handle PUT/DEL methods
962 switch(ehRequest->method)
965 ret = OC_EH_FORBIDDEN;
968 ret = HandlePutRequest(ehRequest);
971 ret = HandlePostRequest(ehRequest);
974 ret = HandleDeleteRequest(ehRequest);
982 //Send payload to request originator
983 ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
990 * This internal method is used to create '/oic/sec/Cred' resource.
992 OCStackResult CreateCredResource()
996 ret = OCCreateResource(&gCredHandle,
997 OIC_RSRC_TYPE_SEC_CRED,
1004 if (OC_STACK_OK != ret)
1006 OIC_LOG (FATAL, TAG, "Unable to instantiate Cred resource");
1007 DeInitCredResource();
1013 * Initialize Cred resource by loading data from persistent storage.
1016 * OC_STACK_OK - no errors
1017 * OC_STACK_ERROR - stack process error
1019 OCStackResult InitCredResource()
1021 OCStackResult ret = OC_STACK_ERROR;
1023 //Read Cred resource from PS
1024 char* jsonSVRDatabase = GetSVRDatabase();
1026 if (jsonSVRDatabase)
1028 //Convert JSON Cred into binary format
1029 gCred = JSONToCredBin(jsonSVRDatabase);
1032 * If SVR database in persistent storage got corrupted or
1033 * is not available for some reason, a default Cred is created
1034 * which allows user to initiate Cred provisioning again.
1036 if (!jsonSVRDatabase || !gCred)
1038 gCred = GetCredDefault();
1040 //Instantiate 'oic.sec.cred'
1041 ret = CreateCredResource();
1042 OICFree(jsonSVRDatabase);
1047 * Perform cleanup for Cred resources.
1050 * OC_STACK_OK - no errors
1051 * OC_STACK_ERROR - stack process error
1052 * OC_STACK_NO_RESOURCE - resource not found
1053 * OC_STACK_INVALID_PARAM - invalid param
1055 OCStackResult DeInitCredResource()
1057 OCStackResult result = OCDeleteResource(gCredHandle);
1058 DeleteCredList(gCred);
1064 * This method is used by tinydtls/SRM to retrieve credential for given Subject.
1066 * @param subject - subject for which credential is required.
1069 * reference to OicSecCred_t - if credential is found
1070 * NULL - if credential not found
1072 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
1074 OicSecCred_t *cred = NULL;
1076 if ( NULL == subject)
1081 LL_FOREACH(gCred, cred)
1083 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
1092 #if defined(__WITH_DTLS__)
1094 * This internal callback is used by lower stack (i.e. CA layer) to
1095 * retrieve PSK credentials from RI security layer.
1097 * @param[in] type type of PSK data required by tinyDTLS layer during DTLS handshake.
1098 * @param[in] desc Additional request information.
1099 * @param[in] desc_len The actual length of desc.
1100 * @param[out] result Must be filled with the requested information.
1101 * @param[in] result_length Maximum size of @p result.
1103 * @return The number of bytes written to @p result or a value
1104 * less than zero on error.
1106 int32_t GetDtlsPskCredentials( CADtlsPskCredType_t type,
1107 const unsigned char *desc, size_t desc_len,
1108 unsigned char *result, size_t result_length)
1119 case CA_DTLS_PSK_HINT:
1120 case CA_DTLS_PSK_IDENTITY:
1122 OicUuid_t deviceID = {.id={}};
1123 // Retrieve Device ID from doxm resource
1124 if ( OC_STACK_OK != GetDoxmDeviceID(&deviceID) )
1126 OIC_LOG (ERROR, TAG, "Unable to retrieve doxm Device ID");
1130 if (result_length < sizeof(deviceID.id))
1132 OIC_LOG (ERROR, TAG, "Wrong value for result_length");
1135 memcpy(result, deviceID.id, sizeof(deviceID.id));
1136 return (sizeof(deviceID.id));
1140 case CA_DTLS_PSK_KEY:
1142 OicSecCred_t *cred = NULL;
1143 LL_FOREACH(gCred, cred)
1145 if (cred->credType != SYMMETRIC_PAIR_WISE_KEY)
1150 if ((desc_len == sizeof(cred->subject.id)) &&
1151 (memcmp(desc, cred->subject.id, sizeof(cred->subject.id)) == 0))
1154 * If the credentials are valid for limited time,
1155 * check their expiry.
1159 if(IOTVTICAL_VALID_ACCESS != IsRequestWithinValidTime(cred->period, NULL))
1161 OIC_LOG (INFO, TAG, "Credentials are expired.");
1167 // Convert PSK from Base64 encoding to binary before copying
1168 uint32_t outLen = 0;
1169 B64Result b64Ret = b64Decode(cred->privateData.data,
1170 strlen(cred->privateData.data), result,
1171 result_length, &outLen);
1172 if (B64_OK != b64Ret)
1174 OIC_LOG (ERROR, TAG, "Base64 decoding failed.");
1186 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
1195 #endif /* __WITH_DTLS__ */
1196 #ifdef __WITH_X509__
1197 #define CERT_LEN_PREFIX (3)
1198 #define BYTE_SIZE (8) //bits
1199 #define PUB_KEY_X_COORD ("x")
1200 #define PUB_KEY_Y_COORD ("y")
1201 #define CERTIFICATE ("x5c")
1202 #define PRIVATE_KEY ("d")
1205 static void WriteCertPrefix(uint8_t *prefix, uint32_t certLen)
1207 for (size_t i = 0; i < CERT_LEN_PREFIX; ++i)
1209 prefix[i] = (certLen >> (BYTE_SIZE * (CERT_LEN_PREFIX - 1 - i))) & 0xFF;
1213 static uint32_t ParseCertPrefix(uint8_t *prefix)
1218 for(int i=0; i < CERT_LEN_PREFIX; ++i)
1220 res |= (((uint32_t) prefix[i]) << ((CERT_LEN_PREFIX - 1 -i) * BYTE_SIZE));
1226 static uint32_t appendCert2Chain(uint8_t *appendPoint, char *cert, uint32_t max_len)
1229 VERIFY_NON_NULL(TAG, appendPoint, ERROR);
1230 VERIFY_NON_NULL(TAG, cert, ERROR);
1233 VERIFY_SUCCESS(TAG, B64_OK == b64Decode(cert, strlen(cert), appendPoint + CERT_LEN_PREFIX,
1234 max_len - CERT_LEN_PREFIX, &certLen), ERROR);
1235 WriteCertPrefix(appendPoint, certLen);
1237 ret = certLen + CERT_LEN_PREFIX;
1242 static OCStackResult GetCAPublicKeyData(CADtlsX509Creds_t *credInfo){
1243 OCStackResult ret = OC_STACK_ERROR;
1244 uint8_t *ccPtr = credInfo->certificateChain;
1245 for(uint32_t i =0; i < credInfo->chainLen - 1; ++i)
1247 ccPtr += CERT_LEN_PREFIX + ParseCertPrefix(ccPtr);
1251 .data = ccPtr + CERT_LEN_PREFIX,
1252 .len = ParseCertPrefix(ccPtr)
1254 CertificateX509 certStruct;
1256 VERIFY_SUCCESS(TAG, PKI_SUCCESS == DecodeCertificate(cert, &certStruct), ERROR);
1258 INC_BYTE_ARRAY(certStruct.pubKey, 2);
1260 memcpy(credInfo->rootPublicKeyX, certStruct.pubKey.data, PUBLIC_KEY_SIZE / 2);
1261 memcpy(credInfo->rootPublicKeyY, certStruct.pubKey.data + PUBLIC_KEY_SIZE / 2, PUBLIC_KEY_SIZE / 2);
1268 static OCStackResult GetCertCredPublicData(CADtlsX509Creds_t *credInfo, OicSecCred_t *cred)
1270 OCStackResult ret = OC_STACK_ERROR;
1271 cJSON *jsonRoot = NULL;
1273 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1274 VERIFY_NON_NULL(TAG, cred, ERROR);
1275 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
1276 //VERIFY_SUCCESS(TAG, NULL == credInfo->certificateChain.data, ERROR);
1277 jsonRoot = cJSON_Parse(cred->publicData.data);
1278 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
1280 //Get certificate chain
1281 cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, CERTIFICATE);//TODO define field names constants
1282 VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_Array == jsonObj->type, ERROR);
1284 size_t certChainLen = (size_t)cJSON_GetArraySize(jsonObj);
1285 credInfo->chainLen = certChainLen;
1286 VERIFY_SUCCESS(TAG, MAX_CHAIN_LEN >= certChainLen, ERROR);
1289 for (size_t i = 0; i < certChainLen; ++i)
1291 cJSON *item = cJSON_GetArrayItem(jsonObj, i);
1292 VERIFY_NON_NULL(TAG, item, ERROR);
1293 VERIFY_SUCCESS(TAG, cJSON_String == item->type, ERROR);
1294 uint32_t appendedLen = appendCert2Chain(credInfo->certificateChain + len, item->valuestring,
1295 MAX_CERT_MESSAGE_LEN - len);
1296 VERIFY_SUCCESS(TAG, 0 != appendedLen, ERROR);
1299 credInfo->certificateChainLen = len;
1300 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCAPublicKeyData(credInfo), ERROR);
1303 cJSON_Delete(jsonRoot);
1307 static OCStackResult GetCertCredPrivateData(CADtlsX509Creds_t *credInfo, OicSecCred_t *cred)
1309 OCStackResult ret = OC_STACK_ERROR;
1310 cJSON *jsonRoot = NULL;
1311 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1312 VERIFY_NON_NULL(TAG, cred, ERROR);
1313 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
1314 jsonRoot = cJSON_Parse(cred->privateData.data);
1315 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
1317 cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, PRIVATE_KEY);//TODO define field names constants
1318 VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_String == jsonObj->type, ERROR);
1321 VERIFY_SUCCESS(TAG, B64_OK == b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
1322 credInfo->devicePrivateKey, PRIVATE_KEY_SIZE, &read)
1323 && PRIVATE_KEY_SIZE == read, ERROR);
1328 cJSON_Delete(jsonRoot);
1332 int GetDtlsX509Credentials(CADtlsX509Creds_t *credInfo)
1335 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1338 VERIFY_SUCCESS(TAG, OC_STACK_OK == InitCredResource(), ERROR);
1341 OicSecCred_t *cred = NULL;
1342 LL_SEARCH_SCALAR(gCred, cred, credType, SIGNED_ASYMMETRIC_KEY);
1343 VERIFY_NON_NULL(TAG, cred, ERROR);
1345 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPrivateData(credInfo, cred), ERROR);
1346 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPublicData(credInfo, cred), ERROR);
1353 #undef CERT_LEN_PREFIX
1354 #endif /* __WITH_X509__ */