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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
23 #include "oic_malloc.h"
25 #include "resourcemanager.h"
26 #include "psinterface.h"
28 #include "srmresourcestrings.h"
29 #include "credresource.h"
31 #include "doxmresource.h"
33 #include "srmutility.h"
34 #include "cainterface.h"
38 #define TAG PCF("SRM-CREDL")
40 static OicSecCred_t *gCred = NULL;
41 static OCResourceHandle gCredHandle = NULL;
43 void DeleteCredList(OicSecCred_t* cred)
47 OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
48 LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
50 LL_DELETE(cred, credTmp1);
52 //Note: Need further clarification on roleID data type
55 OICFree(credTmp1->roleIds);
59 OICFree(credTmp1->publicData.data);
62 OICFree(credTmp1->privateData.data);
65 OICFree(credTmp1->period);
68 OICFree(credTmp1->owners);
70 //Clean Cred node itself
77 * This function converts credential data into JSON format.
78 * Caller needs to invoke 'free' when done using
80 * @param cred pointer to instance of OicSecCred_t structure.
83 * pointer to JSON credential representation - if credential for subjectId found
84 * NULL - if credential for subjectId not found
86 char * BinToCredJSON(const OicSecCred_t * cred)
88 cJSON *jsonRoot = NULL;
93 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
95 B64Result b64Ret = B64_OK;
97 jsonRoot = cJSON_CreateObject();
98 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
100 cJSON *jsonCredArray = NULL;
101 cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME,
102 jsonCredArray = cJSON_CreateArray());
103 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
107 cJSON *jsonCred = cJSON_CreateObject();
108 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
110 //CredID -- Mandatory
111 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId);
113 //Subject -- Mandatory
115 memset(base64Buff, 0, sizeof(base64Buff));
116 b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff,
117 sizeof(base64Buff), &outLen);
118 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
119 cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff);
121 //Note: Need further clarification on roleID data type
123 //RoleId -- Not Mandatory
124 if(cred->roleIdsLen > 0)
126 cJSON *jsonRoleIdsArray = NULL;
127 cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME,
128 jsonRoleIdsArray = cJSON_CreateArray());
129 VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR);
130 for (size_t i = 0; i < cred->roleIdsLen; i++)
132 cJSON_AddItemToArray (jsonRoleIdsArray,
133 cJSON_CreateString((char *)cred->roleIds[i].id));
138 //CredType -- Mandatory
139 cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
142 //PublicData -- Not Mandatory
143 if(cred->publicData.data)
145 cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
148 //PrivateData -- Not Mandatory
149 if(cred->privateData.data)
151 cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
154 //Period -- Not Mandatory
157 cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME,
161 //Owners -- Mandatory
162 cJSON *jsonOwnrArray = NULL;
163 cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME,
164 jsonOwnrArray = cJSON_CreateArray());
165 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
166 for (size_t i = 0; i < cred->ownersLen; i++)
169 memset(base64Buff, 0, sizeof(base64Buff));
170 b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id),
171 base64Buff, sizeof(base64Buff), &outLen);
172 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
173 cJSON_AddItemToArray (jsonOwnrArray,
174 cJSON_CreateString((char *)(base64Buff)));
177 /* Attach current cred node to cred Array */
178 cJSON_AddItemToArray(jsonCredArray, jsonCred);
182 jsonStr = cJSON_PrintUnformatted(jsonRoot);
188 cJSON_Delete(jsonRoot);
194 * This internal method converts JSON cred into binary cred.
196 OicSecCred_t * JSONToCredBin(const char * jsonStr)
198 OCStackResult ret = OC_STACK_ERROR;
199 OicSecCred_t * headCred = NULL;
200 OicSecCred_t * prevCred = NULL;
201 cJSON *jsonCredArray = NULL;
203 cJSON *jsonRoot = cJSON_Parse(jsonStr);
204 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
206 jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
207 VERIFY_NON_NULL(TAG, jsonCredArray, ERROR);
208 if (cJSON_Array == jsonCredArray->type)
210 int numCred = cJSON_GetArraySize(jsonCredArray);
213 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
215 B64Result b64Ret = B64_OK;
217 VERIFY_SUCCESS(TAG, numCred > 0, ERROR);
220 cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx);
221 VERIFY_NON_NULL(TAG, jsonCred, ERROR);
223 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
224 VERIFY_NON_NULL(TAG, cred, ERROR);
226 headCred = (headCred) ? headCred : cred;
229 prevCred->next = cred;
231 size_t jsonObjLen = 0;
232 cJSON *jsonObj = NULL;
234 //CredId -- Mandatory
235 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME);
236 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
237 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR)
238 cred->credId = jsonObj->valueint;
240 //subject -- Mandatory
241 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME);
242 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
243 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR)
245 memset(base64Buff, 0, sizeof(base64Buff));
246 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
247 base64Buff, sizeof(base64Buff), &outLen);
248 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)),
250 memcpy(cred->subject.id, base64Buff, outLen);
252 //CredType -- Mandatory
253 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME);
254 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
255 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR)
256 cred->credType = jsonObj->valueint;
258 //PrivateData is mandatory for some of the credential types listed below.
259 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME);
260 if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) ||
261 (cred->credType & SYMMETRIC_GROUP_KEY) ||
262 (cred->credType & PIN_PASSWORD))
264 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
265 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
267 if(jsonObj && cJSON_String == jsonObj->type)
269 jsonObjLen = strlen(jsonObj->valuestring) + 1;
270 cred->privateData.data = (char *)OICMalloc(jsonObjLen);
271 VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
272 strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
275 //Period -- Not Mandatory
276 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME);
277 if(jsonObj && cJSON_String == jsonObj->type)
279 jsonObjLen = strlen(jsonObj->valuestring) + 1;
280 cred->period = (char *)OICMalloc(jsonObjLen);
281 VERIFY_NON_NULL(TAG, cred->period, ERROR);
282 strncpy(cred->period, jsonObj->valuestring, jsonObjLen);
285 //Owners -- Mandatory
286 jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME);
287 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
288 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR)
289 cred->ownersLen = cJSON_GetArraySize(jsonObj);
290 VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR);
291 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
292 VERIFY_NON_NULL(TAG, (cred->owners), ERROR);
293 for(size_t i = 0; i < cred->ownersLen; i++)
295 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i);
296 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
297 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
299 memset(base64Buff, 0, sizeof(base64Buff));
300 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring),
301 base64Buff, sizeof(base64Buff), &outLen);
302 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK &&
303 outLen <= sizeof(cred->owners[i].id)), ERROR);
304 memcpy(cred->owners[i].id, base64Buff, outLen);
307 } while( ++idx < numCred);
313 cJSON_Delete(jsonRoot);
314 if (OC_STACK_OK != ret)
316 DeleteCredList(headCred);
323 * This function generates the bin credential data.
325 * @param subject pointer to subject of this credential.
326 * @param credType credential type.
327 * @param publicData public data such as public key.
328 * @param privateData private data such as private key.
329 * @param ownersLen length of owners array
330 * @param owners array of owners.
333 * pointer to instance of OicSecCred_t - success
336 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
337 const char * publicData, const char * privateData,
338 size_t ownersLen, const OicUuid_t * owners)
340 OCStackResult ret = OC_STACK_ERROR;
342 OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
343 VERIFY_NON_NULL(TAG, cred, ERROR);
345 //TODO:Need more clarification on credId
346 OCFillRandomMem((uint8_t*)&cred->credId, sizeof(cred->credId));
348 VERIFY_NON_NULL(TAG, subject, ERROR);
349 memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
351 //TODO: check credType has one of the values {0, 1, 2, 4, 6, 8, 16}
352 cred->credType = credType;
357 cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
358 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
359 strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
365 cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1);
366 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
367 strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1);
370 VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
371 cred->ownersLen = ownersLen;
373 cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t));
374 VERIFY_NON_NULL(TAG, cred->owners, ERROR);
375 for(size_t i = 0; i < cred->ownersLen; i++)
377 memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
382 if (OC_STACK_OK != ret)
384 DeleteCredList(cred);
391 * This function adds the new cred to the credential list.
393 * @param cred pointer to new credential.
396 * OC_STACK_OK - cred not NULL and persistent storage gets updated
397 * OC_STACK_ERROR - cred is NULL or fails to update persistent storage
399 OCStackResult AddCredential(OicSecCred_t * newCred)
401 OCStackResult ret = OC_STACK_ERROR;
405 return OC_STACK_ERROR;
408 //Append the new Cred to existing list
409 LL_APPEND(gCred, newCred);
411 //Convert CredList to JSON and update the persistent Storage
412 char * jsonStr = BinToCredJSON(gCred);
416 cJSON *jsonCred = cJSON_Parse(jsonStr);
419 if((jsonCred) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred)))
423 cJSON_Delete(jsonCred);
429 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
431 OCEntityHandlerResult ret = OC_EH_ERROR;
433 //Get binary representation of json
434 OicSecCred_t * cred = JSONToCredBin((char *)ehRequest->reqJSONPayload);
438 //Append the new Cred to existing list
439 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
446 * This internal method is the entity handler for Cred resources
447 * to handle REST request (PUT/POST/DEL)
449 OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag,
450 OCEntityHandlerRequest * ehRequest,
451 void* callbackParameter)
453 OCEntityHandlerResult ret = OC_EH_ERROR;
459 if (flag & OC_REQUEST_FLAG)
461 OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
462 //TODO : Handle PUT/DEL methods
463 switch(ehRequest->method)
466 ret = OC_EH_FORBIDDEN;
469 ret = HandlePostRequest(ehRequest);
477 //Send payload to request originator
478 ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ?
485 * This internal method is used to create '/oic/sec/Cred' resource.
487 OCStackResult CreateCredResource()
491 ret = OCCreateResource(&gCredHandle,
492 OIC_RSRC_TYPE_SEC_CRED,
499 if (OC_STACK_OK != ret)
501 OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource"));
502 DeInitCredResource();
508 * Get the default value
509 * @retval NULL for now. Update it when we finalize the default info.
511 static OicSecCred_t* GetCredDefault()
517 * Initialize Cred resource by loading data from persistent storage.
520 * OC_STACK_OK - no errors
521 * OC_STACK_ERROR - stack process error
523 OCStackResult InitCredResource()
525 OCStackResult ret = OC_STACK_ERROR;
527 //Read Cred resource from PS
528 char* jsonSVRDatabase = GetSVRDatabase();
532 //Convert JSON Cred into binary format
533 gCred = JSONToCredBin(jsonSVRDatabase);
536 * If SVR database in persistent storage got corrupted or
537 * is not available for some reason, a default Cred is created
538 * which allows user to initiate Cred provisioning again.
540 if (!jsonSVRDatabase || !gCred)
542 gCred = GetCredDefault();
544 //Instantiate 'oic.sec.cred'
545 ret = CreateCredResource();
546 OICFree(jsonSVRDatabase);
551 * Perform cleanup for Cred resources.
554 * OC_STACK_OK - no errors
555 * OC_STACK_ERROR - stack process error
556 * OC_STACK_NO_RESOURCE - resource not found
557 * OC_STACK_INVALID_PARAM - invalid param
559 OCStackResult DeInitCredResource()
561 OCStackResult result = OCDeleteResource(gCredHandle);
562 DeleteCredList(gCred);
568 * This method is used by tinydtls/SRM to retrieve credential for given Subject.
570 * @param subject - subject for which credential is required.
573 * reference to OicSecCred_t - if credential is found
574 * NULL - if credential not found
576 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
578 OicSecCred_t *cred = NULL;
580 if ( NULL == subject)
585 LL_FOREACH(gCred, cred)
587 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
596 #if defined(__WITH_DTLS__)
598 * This internal callback is used by lower stack (i.e. CA layer) to
599 * retrieve PSK credentials from RI security layer.
601 * Note: When finished, caller should initialize memory to zeros and
602 * invoke OICFree to delete @p credInfo.
605 * binary blob containing PSK credentials
609 void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo)
611 CADtlsPskCredsBlob_t * caBlob = NULL;
614 caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1);
617 OicUuid_t deviceID = {};
619 // Retrieve Device ID from doxm resource and copy in PSK creds blob
620 VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR);
621 memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity));
623 OicSecCred_t *cred = NULL;
625 LL_FOREACH(gCred, cred)
627 // Currently, Iotivity supports only symmetric pair wise key credentials
628 if (cred->credType == SYMMETRIC_PAIR_WISE_KEY)
637 (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds));
638 VERIFY_NON_NULL(TAG, caBlob->creds, ERROR);
641 LL_FOREACH(gCred, cred)
643 if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) &&
648 memcpy(caBlob->creds[i].id, cred->subject.id,
649 sizeof(caBlob->creds[i].id));
651 // Convert PSK from JSON to binary before copying
653 B64Result b64Ret = b64Decode(cred->privateData.data,
654 strlen(cred->privateData.data), caBlob->creds[i].psk,
655 sizeof(caBlob->creds[i].psk), &outLen);
656 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
663 // Return from here after making the credential list
670 memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds));
671 OICFree(caBlob->creds);
675 #endif /* __WITH_DTLS__ */