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"
45 #define TAG PCF("SRM-CREDL")
48 static OicSecCred_t *gCred = NULL;
49 static OCResourceHandle gCredHandle = NULL;
52 * This function frees OicSecCred_t object's fields and object itself.
54 static void FreeCred(OicSecCred_t *cred)
58 OC_LOG (INFO, TAG, PCF("Invalid Parameter"));
61 //Note: Need further clarification on roleID data type
64 OICFree(cred->roleIds);
68 OICFree(cred->publicData.data);
71 OICFree(cred->privateData.data);
74 OICFree(cred->period);
77 OICFree(cred->owners);
79 //Clean Cred node itself
83 void DeleteCredList(OicSecCred_t* cred)
87 OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
88 LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
90 LL_DELETE(cred, credTmp1);
97 * This function converts credential data into JSON format.
98 * Caller needs to invoke 'free' when done using
100 * @param cred pointer to instance of OicSecCred_t structure.
103 * pointer to JSON credential representation - if credential for subjectId found
104 * NULL - if credential for subjectId not found
106 char * BinToCredJSON(const OicSecCred_t * cred)
108 cJSON *jsonRoot = NULL;
109 char *jsonStr = NULL;
113 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
115 B64Result b64Ret = B64_OK;
117 jsonRoot = cJSON_CreateObject();
118 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
120 cJSON *jsonCredArray = NULL;
121 cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
122 jsonCredArray = cJSON_CreateArray());
123 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
127 cJSON *jsonCred = cJSON_CreateObject();
128 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
130 //CredID -- Mandatory
131 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
133 //Subject -- Mandatory
135 memset(base64Buff, 0, sizeof(base64Buff));
136 b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
137 sizeof(base64Buff), &outLen);
138 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
139 cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
141 //Note: Need further clarification on roleID data type
143 //RoleId -- Not Mandatory
144 if(cred->roleIdsLen > 0)
146 cJSON *jsonRoleIdsArray = NULL;
147 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
148 jsonRoleIdsArray = cJSON_CreateArray());
149 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
150 for (size_t i = 0; i < cred->roleIdsLen; i++)
152 cJSON_AddItemToArray (jsonRoleIdsArray,
153 cJSON_CreateString((char *)cred->roleIds[i].id));
158 //CredType -- Mandatory
159 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
162 //PublicData -- Not Mandatory
163 if(cred->publicData.data)
165 if (SIGNED_ASYMMETRIC_KEY == cred->credType)
167 cJSON_AddItemToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME,
168 cJSON_Parse(cred->publicData.data));
172 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
175 #endif /*__WITH_X509__*/
176 //PrivateData -- Not Mandatory
177 if(cred->privateData.data)
180 if (SIGNED_ASYMMETRIC_KEY == cred->credType)
182 cJSON_AddItemToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME,
183 cJSON_Parse(cred->privateData.data));
187 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
190 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
194 //Period -- Not Mandatory
197 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
201 //Owners -- Mandatory
202 cJSON *jsonOwnrArray = NULL;
203 cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
204 jsonOwnrArray = cJSON_CreateArray());
205 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
206 for (size_t i = 0; i < cred->ownersLen; i++)
209 memset(base64Buff, 0, sizeof(base64Buff));
210 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
211 base64Buff, sizeof(base64Buff), &outLen);
212 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
213 cJSON_AddItemToArray (jsonOwnrArray,
214 cJSON_CreateString((char *)(base64Buff)));
217 /* Attach current cred node to cred Array */
218 cJSON_AddItemToArray(jsonCredArray, jsonCred);
222 jsonStr = cJSON_PrintUnformatted(jsonRoot);
228 cJSON_Delete(jsonRoot);
234 * This internal method converts JSON cred into binary cred.
236 OicSecCred_t * JSONToCredBin(const char * jsonStr)
238 OCStackResult ret = OC_STACK_ERROR;
239 OicSecCred_t * headCred = NULL;
240 OicSecCred_t * prevCred = NULL;
241 cJSON *jsonCredArray = NULL;
243 cJSON *jsonRoot = cJSON_Parse(jsonStr);
244 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
246 jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
247 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
248 if (cJSON_Array == jsonCredArray->type)
250 int numCred = cJSON_GetArraySize(jsonCredArray);
253 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
255 B64Result b64Ret = B64_OK;
257 VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
260 cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
261 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
263 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
264 VERIFY_NON_NULL(TAG, cred, ERROR);
266 headCred = (headCred) ? headCred : cred;
269 prevCred->next = cred;
271 size_t jsonObjLen = 0;
272 cJSON *jsonObj = NULL;
274 //CredId -- Mandatory
275 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
278 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
279 cred->credId = jsonObj->valueint;
282 //subject -- Mandatory
283 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
284 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
285 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
287 memset(base64Buff, 0, sizeof(base64Buff));
288 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
289 base64Buff, sizeof(base64Buff), &outLen);
290 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
292 memcpy(cred->subject.id, base64Buff, outLen);
294 //CredType -- Mandatory
295 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
296 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
297 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
298 cred->credType = jsonObj->valueint;
300 //PrivateData is mandatory for some of the credential types listed below.
301 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
302 if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
303 (cred->credType & SYMMETRIC_GROUP_KEY) ||
304 (cred->credType & PIN_PASSWORD))
306 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
307 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
310 else if (cred->credType & SIGNED_ASYMMETRIC_KEY)
312 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
313 VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
315 #endif // __WITH_X509__
318 if (cJSON_String == jsonObj->type)
320 jsonObjLen = strlen(jsonObj->valuestring) + 1;
321 cred->privateData.data = (char *)OICMalloc(jsonObjLen);
322 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
323 strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
326 else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
328 cred->privateData.data = cJSON_PrintUnformatted(jsonObj);
329 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
331 #endif // __WITH_X509__
334 //PublicData is mandatory only for SIGNED_ASYMMETRIC_KEY credentials type.
335 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PUBLICDATA_NAME);
337 if (cred->credType & SIGNED_ASYMMETRIC_KEY)
339 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
340 VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
342 #endif // __WITH_X509__
345 if (cJSON_String == jsonObj->type)
347 jsonObjLen = strlen(jsonObj->valuestring) + 1;
348 cred->publicData.data = (char *)OICMalloc(jsonObjLen);
349 VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
350 strncpy((char *)cred->publicData.data, (char *)jsonObj->valuestring, jsonObjLen);
353 else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
355 cred->publicData.data = cJSON_PrintUnformatted(jsonObj);
356 VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
358 #endif // __WITH_X509__
361 //Period -- Not Mandatory
362 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
363 if(jsonObj && cJSON_String == jsonObj->type)
365 jsonObjLen = strlen(jsonObj->valuestring) + 1;
366 cred->period = (char *)OICMalloc(jsonObjLen);
367 VERIFY_NON_NULL(TAG, cred->period, ERROR);
368 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
371 //Owners -- Mandatory
372 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
373 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
374 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
375 cred->ownersLen = cJSON_GetArraySize(jsonObj);
376 VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
377 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
378 VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
379 for(size_t i = 0; i < cred->ownersLen; i++)
381 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
382 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
383 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
385 memset(base64Buff, 0, sizeof(base64Buff));
386 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
387 base64Buff, sizeof(base64Buff), &outLen);
388 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
389 outLen <= sizeof(cred->owners[i].id)), ERROR);
390 memcpy(cred->owners[i].id, base64Buff, outLen);
393 } while( ++idx < numCred);
399 cJSON_Delete(jsonRoot);
400 if (OC_STACK_OK != ret)
402 DeleteCredList(headCred);
409 * This function generates the bin credential data.
411 * @param subject pointer to subject of this credential.
412 * @param credType credential type.
413 * @param publicData public data such as public key.
414 * @param privateData private data such as private key.
415 * The privateData is expected in base64 encoded format.
416 * @param ownersLen length of owners array
417 * @param owners array of owners.
420 * pointer to instance of OicSecCred_t - success
423 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
424 const char * publicData, const char * privateData,
425 size_t ownersLen, const OicUuid_t * owners)
428 OCStackResult ret = OC_STACK_ERROR;
430 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
431 VERIFY_NON_NULL(TAG, cred, ERROR);
433 //CredId is assigned before appending new cred to the existing
434 //credential list and updating svr database in AddCredential().
437 VERIFY_NON_NULL(TAG, subject, ERROR);
438 memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
440 VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
441 SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
442 cred->credType = credType;
447 cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
448 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
449 strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
451 #endif // __WITH_X509__
455 cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
456 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
457 strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
460 VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
461 cred->ownersLen = ownersLen;
463 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
464 VERIFY_NON_NULL(TAG, cred->owners, ERROR);
465 for(size_t i = 0; i < cred->ownersLen; i++)
467 memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
472 if (OC_STACK_OK != ret)
474 DeleteCredList(cred);
480 static bool UpdatePersistentStorage(const OicSecCred_t *cred)
484 // Convert Cred data into JSON for update to persistent storage
485 char *jsonStr = BinToCredJSON(cred);
488 cJSON *jsonCred = cJSON_Parse(jsonStr);
492 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
496 cJSON_Delete(jsonCred );
498 else //Empty cred list
500 if (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, NULL))
509 * Compare function used LL_SORT for sorting credentials
511 * @param first pointer to OicSecCred_t struct
512 * @param second pointer to OicSecCred_t struct
515 * -1 if credId of first is less than credId of second
516 * 0 if credId of first is equal to credId of second
517 * 1 if credId of first is greater than credId of second
519 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
521 if(first->credId < second->credId)
525 else if(first->credId > second->credId)
534 * GetCredId goes through the cred list and returns the next
535 * available credId. The next credId could be the credId that is
536 * available due deletion of OicSecCred_t object or one more than
537 * credId of last credential in the list.
540 * next available credId - success
544 static uint16_t GetCredId()
546 //Sorts credential list in incremental order of credId
547 LL_SORT(gCred, CmpCredId);
550 OicSecCred_t *currentCred = NULL, *credTmp = NULL;
551 uint16_t nextCredId = 1;
553 LL_FOREACH_SAFE(gCred, currentCred, credTmp)
555 if(currentCred->credId == nextCredId)
565 VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
574 * This function adds the new cred to the credential list.
576 * @param cred pointer to new credential.
579 * OC_STACK_OK - cred not NULL and persistent storage gets updated
580 * OC_STACK_ERROR - cred is NULL or fails to update persistent storage
582 OCStackResult AddCredential(OicSecCred_t * newCred)
584 OCStackResult ret = OC_STACK_ERROR;
586 VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
588 //Assigning credId to the newCred
589 newCred->credId = GetCredId();
591 VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
593 //Append the new Cred to existing list
594 LL_APPEND(gCred, newCred);
596 if(UpdatePersistentStorage(gCred))
605 OCStackResult RemoveCredential(const OicUuid_t *subject)
607 OCStackResult ret = OC_STACK_ERROR;
608 OicSecCred_t *cred = NULL;
609 OicSecCred_t *tempCred = NULL;
610 bool deleteFlag = false;
612 LL_FOREACH_SAFE(gCred, cred, tempCred)
614 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
616 LL_DELETE(gCred, cred);
624 if(UpdatePersistentStorage(gCred))
626 ret = OC_STACK_RESOURCE_DELETED;
633 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
635 OCEntityHandlerResult ret = OC_EH_ERROR;
637 //Get binary representation of json
638 OicSecCred_t * cred = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
642 //If the Post request credential has credId, it will be
643 //discarded and the next available credId will be assigned
644 //to it before getting appended to the existing credential
645 //list and updating svr database.
646 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
651 static OCEntityHandlerResult HandleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
653 OC_LOG_V (INFO, TAG, PCF("Processing CredDeleteRequest"));
655 OCEntityHandlerResult ehRet = OC_EH_ERROR;
657 if(NULL == ehRequest->query)
662 OicParseQueryIter_t parseIter = {.attrPos=NULL};
663 OicUuid_t subject = {.id={0}};
665 //Parsing REST query to get the subject
666 ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
667 while(GetNextQuery(&parseIter))
669 if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME,
670 parseIter.attrLen) == 0)
672 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
674 B64Result b64Ret = B64_OK;
676 b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen,
677 base64Buff, sizeof(base64Buff), &outLen);
679 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
680 memcpy(subject.id, base64Buff, outLen);
684 if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&subject))
686 ehRet = OC_EH_RESOURCE_DELETED;
694 * This internal method is the entity handler for Cred resources
695 * to handle REST request (PUT/POST/DEL)
697 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
698 OCEntityHandlerRequest * ehRequest,
699 void* callbackParameter)
701 (void)callbackParameter;
702 OCEntityHandlerResult ret = OC_EH_ERROR;
708 if (flag & OC_REQUEST_FLAG)
710 OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
711 //TODO : Handle PUT/DEL methods
712 switch(ehRequest->method)
715 ret = OC_EH_FORBIDDEN;
718 ret = HandlePostRequest(ehRequest);
721 ret = HandleDeleteRequest(ehRequest);
729 //Send payload to request originator
730 ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
737 * This internal method is used to create '/oic/sec/Cred' resource.
739 OCStackResult CreateCredResource()
743 ret = OCCreateResource(&gCredHandle,
744 OIC_RSRC_TYPE_SEC_CRED,
751 if (OC_STACK_OK != ret)
753 OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource"));
754 DeInitCredResource();
760 * Get the default value
761 * @retval NULL for now. Update it when we finalize the default info.
763 static OicSecCred_t* GetCredDefault()
769 * Initialize Cred resource by loading data from persistent storage.
772 * OC_STACK_OK - no errors
773 * OC_STACK_ERROR - stack process error
775 OCStackResult InitCredResource()
777 OCStackResult ret = OC_STACK_ERROR;
779 //Read Cred resource from PS
780 char* jsonSVRDatabase = GetSVRDatabase();
784 //Convert JSON Cred into binary format
785 gCred = JSONToCredBin(jsonSVRDatabase);
788 * If SVR database in persistent storage got corrupted or
789 * is not available for some reason, a default Cred is created
790 * which allows user to initiate Cred provisioning again.
792 if (!jsonSVRDatabase || !gCred)
794 gCred = GetCredDefault();
796 //Instantiate 'oic.sec.cred'
797 ret = CreateCredResource();
798 OICFree(jsonSVRDatabase);
803 * Perform cleanup for Cred resources.
806 * OC_STACK_OK - no errors
807 * OC_STACK_ERROR - stack process error
808 * OC_STACK_NO_RESOURCE - resource not found
809 * OC_STACK_INVALID_PARAM - invalid param
811 OCStackResult DeInitCredResource()
813 OCStackResult result = OCDeleteResource(gCredHandle);
814 DeleteCredList(gCred);
820 * This method is used by tinydtls/SRM to retrieve credential for given Subject.
822 * @param subject - subject for which credential is required.
825 * reference to OicSecCred_t - if credential is found
826 * NULL - if credential not found
828 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
830 OicSecCred_t *cred = NULL;
832 if ( NULL == subject)
837 LL_FOREACH(gCred, cred)
839 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
848 #if defined(__WITH_DTLS__)
850 * This internal callback is used by lower stack (i.e. CA layer) to
851 * retrieve PSK credentials from RI security layer.
853 * Note: When finished, caller should initialize memory to zeros and
854 * invoke OICFree to delete @p credInfo.
857 * binary blob containing PSK credentials
861 void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo)
863 CADtlsPskCredsBlob_t * caBlob = NULL;
866 caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1);
869 OicUuid_t deviceID = {.id={}};
871 // Retrieve Device ID from doxm resource and copy in PSK creds blob
872 VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR);
873 memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity));
875 OicSecCred_t *cred = NULL;
877 LL_FOREACH(gCred, cred)
879 // Currently, Iotivity supports only symmetric pair wise key credentials
880 if (cred->credType == SYMMETRIC_PAIR_WISE_KEY)
889 (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds));
890 VERIFY_NON_NULL(TAG, caBlob->creds, ERROR);
893 LL_FOREACH(gCred, cred)
895 if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) &&
900 memcpy(caBlob->creds[i].id, cred->subject.id,
901 sizeof(caBlob->creds[i].id));
903 // Convert PSK from JSON to binary before copying
905 B64Result b64Ret = b64Decode(cred->privateData.data,
906 strlen(cred->privateData.data), caBlob->creds[i].psk,
907 sizeof(caBlob->creds[i].psk), &outLen);
908 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
915 // Return from here after making the credential list
922 memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds));
923 OICFree(caBlob->creds);
929 * Add temporal PSK to PIN based OxM
931 * @param[in] tmpSubject UUID of target device
932 * @param[in] credType Type of credential to be added
933 * @param[in] pin numeric characters
934 * @param[in] pinSize length of 'pin'
935 * @param[in] ownersLen Number of owners
936 * @param[in] owners Array of owners
937 * @param[out] tmpCredSubject Generated credential's subject.
939 * @return OC_STACK_OK for success and errorcode otherwise.
941 OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t credType,
942 const char * pin, size_t pinSize,
943 size_t ownersLen, const OicUuid_t * owners, OicUuid_t* tmpCredSubject)
945 OCStackResult ret = OC_STACK_ERROR;
947 if(tmpSubject == NULL || pin == NULL || pinSize == 0 || tmpCredSubject == NULL)
949 return OC_STACK_INVALID_PARAM;
952 uint8_t privData[OWNER_PSK_LENGTH_128] = {0,};
953 int dtlsRes = DeriveCryptoKeyFromPassword((const unsigned char *)pin, pinSize, owners->id,
954 UUID_LENGTH, PBKDF_ITERATIONS,
955 OWNER_PSK_LENGTH_128, privData);
956 VERIFY_SUCCESS(TAG, (dtlsRes == 0) , ERROR);
959 char base64Buff[B64ENCODE_OUT_SAFESIZE(OWNER_PSK_LENGTH_128) + 1] = {};
960 B64Result b64Ret = b64Encode(privData, OWNER_PSK_LENGTH_128, base64Buff,
961 sizeof(base64Buff), &outLen);
962 VERIFY_SUCCESS(TAG, (B64_OK == b64Ret), ERROR);
964 OicSecCred_t* cred = GenerateCredential(tmpSubject, credType, NULL,
965 base64Buff, ownersLen, owners);
968 OC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to generate credential");
969 return OC_STACK_ERROR;
972 memcpy(tmpCredSubject->id, cred->subject.id, UUID_LENGTH);
974 ret = AddCredential(cred);
975 if( OC_STACK_OK != ret)
977 OC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to add credential");
984 #endif /* __WITH_DTLS__ */
986 #define CERT_LEN_PREFIX (3)
987 #define BYTE_SIZE (8) //bits
988 #define PUB_KEY_X_COORD ("x")
989 #define PUB_KEY_Y_COORD ("y")
990 #define CERTIFICATE ("x5c")
991 #define PRIVATE_KEY ("d")
994 static void WriteCertPrefix(uint8_t *prefix, uint32_t certLen)
996 for (size_t i = 0; i < CERT_LEN_PREFIX; ++i)
998 prefix[i] = (certLen >> (BYTE_SIZE * (CERT_LEN_PREFIX - 1 - i))) & 0xFF;
1002 static uint32_t ParseCertPrefix(uint8_t *prefix)
1007 for(int i=0; i < CERT_LEN_PREFIX; ++i)
1009 res |= (((uint32_t) prefix[i]) << ((CERT_LEN_PREFIX - 1 -i) * BYTE_SIZE));
1015 static uint32_t appendCert2Chain(uint8_t *appendPoint, char *cert, uint32_t max_len)
1018 VERIFY_NON_NULL(TAG, appendPoint, ERROR);
1019 VERIFY_NON_NULL(TAG, cert, ERROR);
1022 VERIFY_SUCCESS(TAG, B64_OK == b64Decode(cert, strlen(cert), appendPoint + CERT_LEN_PREFIX,
1023 max_len - CERT_LEN_PREFIX, &certLen), ERROR);
1024 WriteCertPrefix(appendPoint, certLen);
1026 ret = certLen + CERT_LEN_PREFIX;
1031 static OCStackResult GetCAPublicKeyData(CADtlsCertCreds_t *credInfo){
1032 OCStackResult ret = OC_STACK_ERROR;
1033 uint8_t *ccPtr = credInfo->certificateChain;
1034 for(uint32_t i =0; i < credInfo->chainLen - 1; ++i)
1036 ccPtr += CERT_LEN_PREFIX + ParseCertPrefix(ccPtr);
1040 .data = ccPtr + CERT_LEN_PREFIX,
1041 .len = ParseCertPrefix(ccPtr)
1043 CertificateX509 certStruct;
1045 VERIFY_SUCCESS(TAG, PKI_SUCCESS == DecodeCertificate(cert, &certStruct), ERROR);
1047 INC_BYTE_ARRAY(certStruct.pubKey, 2);
1049 memcpy(credInfo->rootPublicKeyX, certStruct.pubKey.data, PUBLIC_KEY_SIZE / 2);
1050 memcpy(credInfo->rootPublicKeyY, certStruct.pubKey.data + PUBLIC_KEY_SIZE / 2, PUBLIC_KEY_SIZE / 2);
1057 static OCStackResult GetCertCredPublicData(CADtlsCertCreds_t *credInfo, OicSecCred_t *cred)
1059 OCStackResult ret = OC_STACK_ERROR;
1060 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1061 VERIFY_NON_NULL(TAG, cred, ERROR);
1062 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
1063 //VERIFY_SUCCESS(TAG, NULL == credInfo->certificateChain.data, ERROR);
1064 cJSON *jsonRoot = cJSON_Parse(cred->publicData.data);
1065 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
1067 //Get certificate chain
1068 cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, CERTIFICATE);//TODO define field names constants
1069 VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_Array == jsonObj->type, ERROR);
1071 size_t certChainLen = cJSON_GetArraySize(jsonObj);
1072 credInfo->chainLen = certChainLen;
1073 VERIFY_SUCCESS(TAG, MAX_CHAIN_LEN >= certChainLen, ERROR);
1076 for (size_t i = 0; i < certChainLen; ++i)
1078 cJSON *item = cJSON_GetArrayItem(jsonObj, i);
1079 VERIFY_SUCCESS(TAG, cJSON_String == item->type, ERROR);
1080 uint32_t appendedLen = appendCert2Chain(credInfo->certificateChain + len, item->valuestring,
1081 MAX_REQUEST_LENGTH - len);
1082 VERIFY_SUCCESS(TAG, 0 != appendedLen, ERROR);
1085 credInfo->certificateChainLen = len;
1086 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCAPublicKeyData(credInfo), ERROR);
1089 cJSON_Delete(jsonRoot);
1093 static OCStackResult GetCertCredPrivateData(CADtlsCertCreds_t *credInfo, OicSecCred_t *cred)
1095 OCStackResult ret = OC_STACK_ERROR;
1096 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1097 VERIFY_NON_NULL(TAG, cred, ERROR);
1098 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
1099 cJSON *jsonRoot = cJSON_Parse(cred->privateData.data);
1100 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
1102 cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, PRIVATE_KEY);//TODO define field names constants
1103 VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_String == jsonObj->type, ERROR);
1106 VERIFY_SUCCESS(TAG, B64_OK == b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
1107 credInfo->devicePrivateKey, PRIVATE_KEY_SIZE, &read)
1108 && PRIVATE_KEY_SIZE == read, ERROR);
1113 cJSON_Delete(jsonRoot);
1117 OCStackResult GetDtlsCertCredentials(CADtlsCertCreds_t *credInfo)
1119 OCStackResult ret = OC_STACK_ERROR;
1120 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1123 VERIFY_SUCCESS(TAG, OC_STACK_OK == InitCredResource(), ERROR);
1126 OicSecCred_t *cred = NULL;
1127 LL_SEARCH_SCALAR(gCred, cred, credType, SIGNED_ASYMMETRIC_KEY);
1128 VERIFY_NON_NULL(TAG, cred, ERROR);
1130 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPrivateData(credInfo, cred), ERROR);
1131 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPublicData(credInfo, cred), ERROR);
1138 #undef CERT_LEN_PREFIX
1139 #endif /* __WITH_X509__ */