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"
41 #define TAG PCF("SRM-CREDL")
43 static OicSecCred_t *gCred = NULL;
44 static OCResourceHandle gCredHandle = NULL;
46 void DeleteCredList(OicSecCred_t* cred)
50 OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
51 LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
53 LL_DELETE(cred, credTmp1);
55 //Note: Need further clarification on roleID data type
58 OICFree(credTmp1->roleIds);
62 OICFree(credTmp1->publicData.data);
65 OICFree(credTmp1->privateData.data);
68 OICFree(credTmp1->period);
71 OICFree(credTmp1->owners);
73 //Clean Cred node itself
80 * This function converts credential data into JSON format.
81 * Caller needs to invoke 'free' when done using
83 * @param cred pointer to instance of OicSecCred_t structure.
86 * pointer to JSON credential representation - if credential for subjectId found
87 * NULL - if credential for subjectId not found
89 char * BinToCredJSON(const OicSecCred_t * cred)
91 cJSON *jsonRoot = NULL;
96 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
98 B64Result b64Ret = B64_OK;
100 jsonRoot = cJSON_CreateObject();
101 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
103 cJSON *jsonCredArray = NULL;
104 cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
105 jsonCredArray = cJSON_CreateArray());
106 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
110 cJSON *jsonCred = cJSON_CreateObject();
111 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
113 //CredID -- Mandatory
114 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
116 //Subject -- Mandatory
118 memset(base64Buff, 0, sizeof(base64Buff));
119 b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
120 sizeof(base64Buff), &outLen);
121 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
122 cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
124 //Note: Need further clarification on roleID data type
126 //RoleId -- Not Mandatory
127 if(cred->roleIdsLen > 0)
129 cJSON *jsonRoleIdsArray = NULL;
130 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
131 jsonRoleIdsArray = cJSON_CreateArray());
132 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
133 for (size_t i = 0; i < cred->roleIdsLen; i++)
135 cJSON_AddItemToArray (jsonRoleIdsArray,
136 cJSON_CreateString((char *)cred->roleIds[i].id));
141 //CredType -- Mandatory
142 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
145 //PublicData -- Not Mandatory
146 if(cred->publicData.data)
148 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
151 //PrivateData -- Not Mandatory
152 if(cred->privateData.data)
154 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
157 //Period -- Not Mandatory
160 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
164 //Owners -- Mandatory
165 cJSON *jsonOwnrArray = NULL;
166 cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
167 jsonOwnrArray = cJSON_CreateArray());
168 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
169 for (size_t i = 0; i < cred->ownersLen; i++)
172 memset(base64Buff, 0, sizeof(base64Buff));
173 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
174 base64Buff, sizeof(base64Buff), &outLen);
175 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
176 cJSON_AddItemToArray (jsonOwnrArray,
177 cJSON_CreateString((char *)(base64Buff)));
180 /* Attach current cred node to cred Array */
181 cJSON_AddItemToArray(jsonCredArray, jsonCred);
185 jsonStr = cJSON_PrintUnformatted(jsonRoot);
191 cJSON_Delete(jsonRoot);
197 * This internal method converts JSON cred into binary cred.
199 OicSecCred_t * JSONToCredBin(const char * jsonStr)
201 OCStackResult ret = OC_STACK_ERROR;
202 OicSecCred_t * headCred = NULL;
203 OicSecCred_t * prevCred = NULL;
204 cJSON *jsonCredArray = NULL;
206 cJSON *jsonRoot = cJSON_Parse(jsonStr);
207 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
209 jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
210 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
211 if (cJSON_Array == jsonCredArray->type)
213 int numCred = cJSON_GetArraySize(jsonCredArray);
216 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
218 B64Result b64Ret = B64_OK;
220 VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
223 cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
224 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
226 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
227 VERIFY_NON_NULL(TAG, cred, ERROR);
229 headCred = (headCred) ? headCred : cred;
232 prevCred->next = cred;
234 size_t jsonObjLen = 0;
235 cJSON *jsonObj = NULL;
237 //CredId -- Mandatory
238 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
241 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
242 cred->credId = jsonObj->valueint;
245 //subject -- Mandatory
246 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
247 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
248 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
250 memset(base64Buff, 0, sizeof(base64Buff));
251 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
252 base64Buff, sizeof(base64Buff), &outLen);
253 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
255 memcpy(cred->subject.id, base64Buff, outLen);
257 //CredType -- Mandatory
258 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
259 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
260 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
261 cred->credType = jsonObj->valueint;
263 //PrivateData is mandatory for some of the credential types listed below.
264 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
265 if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
266 (cred->credType & SYMMETRIC_GROUP_KEY) ||
267 (cred->credType & PIN_PASSWORD))
269 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
270 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
272 if(jsonObj && cJSON_String == jsonObj->type)
274 jsonObjLen = strlen(jsonObj->valuestring) + 1;
275 cred->privateData.data = (char *)OICMalloc(jsonObjLen);
276 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
277 strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
280 //Period -- Not Mandatory
281 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
282 if(jsonObj && cJSON_String == jsonObj->type)
284 jsonObjLen = strlen(jsonObj->valuestring) + 1;
285 cred->period = (char *)OICMalloc(jsonObjLen);
286 VERIFY_NON_NULL(TAG, cred->period, ERROR);
287 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
290 //Owners -- Mandatory
291 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
292 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
293 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR)
294 cred->ownersLen = cJSON_GetArraySize(jsonObj);
295 VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
296 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
297 VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
298 for(size_t i = 0; i < cred->ownersLen; i++)
300 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
301 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
302 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
304 memset(base64Buff, 0, sizeof(base64Buff));
305 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
306 base64Buff, sizeof(base64Buff), &outLen);
307 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
308 outLen <= sizeof(cred->owners[i].id)), ERROR);
309 memcpy(cred->owners[i].id, base64Buff, outLen);
312 } while( ++idx < numCred);
318 cJSON_Delete(jsonRoot);
319 if (OC_STACK_OK != ret)
321 DeleteCredList(headCred);
328 * This function generates the bin credential data.
330 * @param subject pointer to subject of this credential.
331 * @param credType credential type.
332 * @param publicData public data such as public key.
333 * @param privateData private data such as private key.
334 * The privateData is expected in base64 encoded format.
335 * @param ownersLen length of owners array
336 * @param owners array of owners.
339 * pointer to instance of OicSecCred_t - success
342 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
343 const char * publicData, const char * privateData,
344 size_t ownersLen, const OicUuid_t * owners)
346 OCStackResult ret = OC_STACK_ERROR;
348 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
349 VERIFY_NON_NULL(TAG, cred, ERROR);
351 //CredId is assigned before appending new cred to the existing
352 //credential list and updating svr database in AddCredential().
355 VERIFY_NON_NULL(TAG, subject, ERROR);
356 memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
358 VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
359 SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
360 cred->credType = credType;
365 cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
366 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
367 strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
373 cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
374 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
375 strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
378 VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
379 cred->ownersLen = ownersLen;
381 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
382 VERIFY_NON_NULL(TAG, cred->owners, ERROR);
383 for(size_t i = 0; i < cred->ownersLen; i++)
385 memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
390 if (OC_STACK_OK != ret)
392 DeleteCredList(cred);
399 * Compare function used LL_SORT for sorting credentials
401 * @param first pointer to OicSecCred_t struct
402 * @param second pointer to OicSecCred_t struct
405 * -1 if credId of first is less than credId of second
406 * 0 if credId of first is equal to credId of second
407 * 1 if credId of first is greater than credId of second
409 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
411 if(first->credId < second->credId)
415 else if(first->credId > second->credId)
424 * GetCredId goes through the cred list and returns the next
425 * available credId. The next credId could be the credId that is
426 * available due deletion of OicSecCred_t object or one more than
427 * credId of last credential in the list.
430 * next available credId - success
434 static uint16_t GetCredId()
436 //Sorts credential list in incremental order of credId
437 LL_SORT(gCred, CmpCredId);
440 OicSecCred_t *currentCred = NULL, *credTmp = NULL;
441 uint16_t nextCredId = 1;
443 LL_FOREACH_SAFE(gCred, currentCred, credTmp)
445 if(currentCred->credId == nextCredId)
455 VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
462 * This function adds the new cred to the credential list.
464 * @param cred pointer to new credential.
467 * OC_STACK_OK - cred not NULL and persistent storage gets updated
468 * OC_STACK_ERROR - cred is NULL or fails to update persistent storage
470 OCStackResult AddCredential(OicSecCred_t * newCred)
472 OCStackResult ret = OC_STACK_ERROR;
473 char * jsonStr = NULL;
475 VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
477 //Assigning credId to the newCred
478 newCred->credId = GetCredId();
480 VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
482 //Append the new Cred to existing list
483 LL_APPEND(gCred, newCred);
485 //Convert CredList to JSON and update the persistent Storage
486 jsonStr = BinToCredJSON(gCred);
490 cJSON *jsonCred = cJSON_Parse(jsonStr);
493 if((jsonCred) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
497 cJSON_Delete(jsonCred);
504 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
506 OCEntityHandlerResult ret = OC_EH_ERROR;
508 //Get binary representation of json
509 OicSecCred_t * cred = JSONToCredBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
513 //If the Post request credential has credId, it will be
514 //discarded and the next available credId will be assigned
515 //to it before getting appended to the existing credential
516 //list and updating svr database.
517 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
524 * This internal method is the entity handler for Cred resources
525 * to handle REST request (PUT/POST/DEL)
527 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
528 OCEntityHandlerRequest * ehRequest,
529 void* callbackParameter)
531 OCEntityHandlerResult ret = OC_EH_ERROR;
537 if (flag & OC_REQUEST_FLAG)
539 OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
540 //TODO : Handle PUT/DEL methods
541 switch(ehRequest->method)
544 ret = OC_EH_FORBIDDEN;
547 ret = HandlePostRequest(ehRequest);
555 //Send payload to request originator
556 ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
563 * This internal method is used to create '/oic/sec/Cred' resource.
565 OCStackResult CreateCredResource()
569 ret = OCCreateResource(&gCredHandle,
570 OIC_RSRC_TYPE_SEC_CRED,
577 if (OC_STACK_OK != ret)
579 OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource"));
580 DeInitCredResource();
586 * Get the default value
587 * @retval NULL for now. Update it when we finalize the default info.
589 static OicSecCred_t* GetCredDefault()
595 * Initialize Cred resource by loading data from persistent storage.
598 * OC_STACK_OK - no errors
599 * OC_STACK_ERROR - stack process error
601 OCStackResult InitCredResource()
603 OCStackResult ret = OC_STACK_ERROR;
605 //Read Cred resource from PS
606 char* jsonSVRDatabase = GetSVRDatabase();
610 //Convert JSON Cred into binary format
611 gCred = JSONToCredBin(jsonSVRDatabase);
614 * If SVR database in persistent storage got corrupted or
615 * is not available for some reason, a default Cred is created
616 * which allows user to initiate Cred provisioning again.
618 if (!jsonSVRDatabase || !gCred)
620 gCred = GetCredDefault();
622 //Instantiate 'oic.sec.cred'
623 ret = CreateCredResource();
624 OICFree(jsonSVRDatabase);
629 * Perform cleanup for Cred resources.
632 * OC_STACK_OK - no errors
633 * OC_STACK_ERROR - stack process error
634 * OC_STACK_NO_RESOURCE - resource not found
635 * OC_STACK_INVALID_PARAM - invalid param
637 OCStackResult DeInitCredResource()
639 OCStackResult result = OCDeleteResource(gCredHandle);
640 DeleteCredList(gCred);
646 * This method is used by tinydtls/SRM to retrieve credential for given Subject.
648 * @param subject - subject for which credential is required.
651 * reference to OicSecCred_t - if credential is found
652 * NULL - if credential not found
654 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
656 OicSecCred_t *cred = NULL;
658 if ( NULL == subject)
663 LL_FOREACH(gCred, cred)
665 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
674 #if defined(__WITH_DTLS__)
676 * This internal callback is used by lower stack (i.e. CA layer) to
677 * retrieve PSK credentials from RI security layer.
679 * Note: When finished, caller should initialize memory to zeros and
680 * invoke OICFree to delete @p credInfo.
683 * binary blob containing PSK credentials
687 void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo)
689 CADtlsPskCredsBlob_t * caBlob = NULL;
692 caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1);
695 OicUuid_t deviceID = {};
697 // Retrieve Device ID from doxm resource and copy in PSK creds blob
698 VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR);
699 memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity));
701 OicSecCred_t *cred = NULL;
703 LL_FOREACH(gCred, cred)
705 // Currently, Iotivity supports only symmetric pair wise key credentials
706 if (cred->credType == SYMMETRIC_PAIR_WISE_KEY)
715 (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds));
716 VERIFY_NON_NULL(TAG, caBlob->creds, ERROR);
719 LL_FOREACH(gCred, cred)
721 if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) &&
726 memcpy(caBlob->creds[i].id, cred->subject.id,
727 sizeof(caBlob->creds[i].id));
729 // Convert PSK from JSON to binary before copying
731 B64Result b64Ret = b64Decode(cred->privateData.data,
732 strlen(cred->privateData.data), caBlob->creds[i].psk,
733 sizeof(caBlob->creds[i].psk), &outLen);
734 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
741 // Return from here after making the credential list
748 memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds));
749 OICFree(caBlob->creds);
753 #endif /* __WITH_DTLS__ */