1 //******************************************************************
3 // Copyright 2015 Samsung Electronics 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 "EnrolleeSecurity.h"
24 #include "oxmjustworks.h"
25 #include "oxmrandompin.h"
26 #include "EnrolleeResource.h"
28 #include "ESException.h"
29 #include "oic_malloc.h"
30 #include "provisioningdatabasemanager.h"
31 #include "oic_string.h"
33 #include "srmutility.h"
39 #define MAX_PERMISSION_LENGTH (5)
46 #define DISCOVERY_TIMEOUT (10)
48 //TODO : Currently discovery timeout for owned and unowned devices is fixed as 5
49 // The value should be accepted from the application as a parameter during ocplatform
51 #define ES_SEC_DISCOVERY_TIMEOUT 5
53 EnrolleeSecurity::EnrolleeSecurity(
54 std::shared_ptr< OC::OCResource > resource,
55 const std::string secDbPath)
58 m_ocResource = resource;
61 void EnrolleeSecurity::registerCallbackHandler(
62 const SecurityProvStatusCb securityProvStatusCb,
63 const SecurityPinCb securityPinCb,
64 const SecProvisioningDbPathCb secProvisioningDbPathCb)
66 m_securityProvStatusCb = securityProvStatusCb;
67 m_securityPinCb = securityPinCb;
68 m_secProvisioningDbPathCb = secProvisioningDbPathCb;
71 void EnrolleeSecurity::convertUUIDToString(const uint8_t uuid[UUID_SIZE],
72 std::string& uuidString)
74 char uuidArray[UUID_STRING_SIZE] = {'\0',};
75 int ret = snprintf(uuidArray, UUID_STRING_SIZE,
76 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
77 uuid[0], uuid[1], uuid[2], uuid[3],
78 uuid[4], uuid[5], uuid[6], uuid[7],
79 uuid[8], uuid[9], uuid[10], uuid[11],
80 uuid[12], uuid[13], uuid[14], uuid[15]
83 if (ret != UUID_STRING_SIZE - 1)
88 uuidString = uuidArray;
91 void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
95 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
100 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
101 for (unsigned int i = 0; i < result->size(); i++)
103 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
111 ESResult EnrolleeSecurity::provisionOwnership()
113 ESResult res = ESResult::ES_ERROR;
115 OCStackResult result = OC_STACK_ERROR;
117 ConvertStrToUuid(m_ocResource->sid().c_str(), &uuid);
119 result = OCSecure::discoverSingleDevice(ES_SEC_DISCOVERY_TIMEOUT,
122 if (result != OC_STACK_OK)
124 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Secure Resource Discovery failed.");
125 res = ESResult:: ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
128 else if (m_securedResource)
130 if (m_securedResource->getOwnedStatus()) // owned check logic
132 if(isOwnedDeviceRegisteredInSVRDB())
134 res = ESResult::ES_OK;
138 res = ESResult::ES_ERROR;
142 else // unowned check logic
144 if(isOwnedDeviceRegisteredInSVRDB())
146 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
147 "Found Unowned device's DevID at DB of ownedDevices list");
149 OC::ResultCallBack removeDeviceWithUuidCB = std::bind(
150 &EnrolleeSecurity::removeDeviceWithUuidCB,
151 this, std::placeholders::_1, std::placeholders::_2);
153 result = OCSecure::removeDeviceWithUuid(ES_SEC_DISCOVERY_TIMEOUT,
155 removeDeviceWithUuidCB);
156 if(result != OC_STACK_OK)
158 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "removeDeviceWithUuid failed.");
159 res = ESResult::ES_OWNERSHIP_TRANSFER_FAILURE;
163 std::unique_lock<std::mutex> lck(m_mtx);
164 m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
166 if(!removeDeviceResult)
168 res = ESResult::ES_OWNERSHIP_TRANSFER_FAILURE;
173 res = performOwnershipTransfer();
175 if(res != ESResult::ES_OK)
177 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Ownership-Transfer failed.");
178 res = ESResult::ES_OWNERSHIP_TRANSFER_FAILURE;
182 std::unique_lock<std::mutex> lck(m_mtx);
187 res = ESResult::ES_OWNERSHIP_TRANSFER_FAILURE;
193 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No secure resource found.");
194 res = ESResult:: ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
199 ESResult EnrolleeSecurity::performOwnershipTransfer()
201 OCStackResult result = OC_STACK_ERROR;
203 OTMCallbackData_t justWorksCBData;
204 justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
205 justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
206 justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
207 justWorksCBData.createOwnerTransferPayloadCB =
208 CreateJustWorksOwnerTransferPayload;
209 OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
211 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
212 m_securedResource->getDeviceID().c_str());
214 OC::ResultCallBack ownershipTransferCb = std::bind(
215 &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
216 std::placeholders::_2);
218 result = m_securedResource->doOwnershipTransfer(ownershipTransferCb);
219 if (result != OC_STACK_OK)
221 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "doOwnershipTransfer is failed");
222 return ESResult::ES_ERROR;
224 return ESResult::ES_OK;
227 void EnrolleeSecurity::removeDeviceWithUuidCB(OC::PMResultList_t *result, int hasError)
231 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in removeDeviceWithUuid operation!");
232 removeDeviceResult = false;
237 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
239 for (unsigned int i = 0; i < result->size(); i++)
242 convertUUIDToString(result->at(i).deviceId.id, uuid);
244 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
245 "Result is = %d for device %s", result->at(i).res, uuid.c_str());
247 removeDeviceResult = true;
252 bool EnrolleeSecurity::isOwnedDeviceRegisteredInSVRDB()
254 OCStackResult res = OC_STACK_ERROR;
256 OCUuidList_t *uuidList = NULL;
257 size_t numOfDevices = 0;
259 res = PDMGetOwnedDevices(&uuidList, &numOfDevices);
260 if (OC_STACK_OK != res)
262 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while getting info from DB");
266 OCUuidList_t *pUuidList = uuidList;
271 convertUUIDToString(pUuidList->dev.id, uuid);
272 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
273 "m_ocResource->sid(): %s, cur DB UUID %s",
274 m_ocResource->sid().c_str(), uuid.c_str());
275 if(m_ocResource->sid() == uuid.c_str())
279 pUuidList = pUuidList->next;
285 std::string EnrolleeSecurity::getUUID() const
287 return m_ocResource->sid();
290 #if defined(__WITH_DTLS__) && defined(__WITH_TLS__)
291 ESResult EnrolleeSecurity::provisionSecurityForCloudServer(
292 std::string cloudUuid, int credId)
294 ESResult res = ESResult::ES_ERROR;
296 // Need to discover Owned device in a given network, again
297 std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
299 OCStackResult result;
301 ConvertStrToUuid(m_ocResource->sid().c_str(), &uuid);
303 result = OCSecure::discoverSingleDevice(ES_SEC_DISCOVERY_TIMEOUT,
306 if (result != OC_STACK_OK)
308 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "secureResource Discovery failed.");
309 res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
312 else if (ownedDevice)
314 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found secureResource.");
316 if (ownedDevice->getOwnedStatus())
318 if(!isOwnedDeviceRegisteredInSVRDB())
320 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
321 "Not found matched owned deivce in SVR DB.");
322 res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
328 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Target Enrollee is unowned.");
329 res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
335 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found secureResource.");
336 res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
340 if(cloudUuid.empty())
342 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
343 "ACL provisioning is skipped due to empty UUID of cloud server");
347 res = performACLProvisioningForCloudServer(ownedDevice, cloudUuid);
348 if(res != ESResult::ES_OK)
350 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performACLProvisioningForCloudServer");
357 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
358 "Cert. provisioning is skipped due to wrong cred ID (<1)");
362 res = performCertProvisioningForCloudServer(ownedDevice, credId);
363 if(res != ESResult::ES_OK)
365 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performCertProvisioningForCloudServer");
373 ESResult EnrolleeSecurity::performCertProvisioningForCloudServer(
374 std::shared_ptr< OC::OCSecureResource > ownedDevice, int credId)
376 ESResult res = ESResult::ES_CERT_PROVISIONING_FAILURE;
380 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
383 OC::ResultCallBack CertProvisioningCb = std::bind(
384 &EnrolleeSecurity::CertProvisioningCb, this, std::placeholders::_1,
385 std::placeholders::_2);
386 OCStackResult rst = ownedDevice->provisionTrustCertChain(SIGNED_ASYMMETRIC_KEY,
387 static_cast<uint16_t>(credId),
389 if(OC_STACK_OK != rst)
391 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "provisionTrustCertChain error: %d", rst);
395 std::unique_lock<std::mutex> lck(m_mtx);
400 res = ESResult::ES_OK;
406 ESResult EnrolleeSecurity::performACLProvisioningForCloudServer(
407 std::shared_ptr< OC::OCSecureResource > ownedDevice, std::string& cloudUuid)
409 ESResult res = ESResult::ES_ACL_PROVISIONING_FAILURE;
413 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
418 ConvertStrToUuid(cloudUuid.c_str(), &uuid);
420 // Create Acl for Cloud Server to be provisioned to Enrollee
421 OicSecAcl_t* acl = createAcl(uuid);
424 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
428 OC::ResultCallBack aclProvisioningCb = std::bind(
429 &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
430 std::placeholders::_2);
431 // ACL provisioning to Enrollee
432 OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
433 if(OC_STACK_OK != rst)
435 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
439 std::unique_lock<std::mutex> lck(m_mtx);
444 res = ESResult::ES_OK;
450 OicSecAcl_t* EnrolleeSecurity::createAcl(const OicUuid_t cloudUuid)
452 // allocate memory for |acl| struct
453 OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
456 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
457 return NULL; // not need to 'goto' |ERROR| before allocating |acl|
459 OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
462 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
463 return NULL; // not need to 'goto' |ERROR| before allocating |acl|
465 LL_APPEND(acl->aces, ace);
467 memcpy(&ace->subjectuuid, &cloudUuid, UUID_LENGTH);
469 OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
472 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
473 OCDeleteACLList(acl);
478 size_t len = strlen(href)+1; // '1' for null termination
479 rsrc->href = (char*) OICCalloc(len, sizeof(char));
482 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
483 OCDeleteACLList(acl);
486 OICStrcpy(rsrc->href, len, href);
489 rsrc->typeLen = arrLen;
490 rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
491 rsrc->interfaceLen = 1;
492 rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
493 rsrc->types[0] = OICStrdup("rt"); // ignore
494 rsrc->interfaces[0] = OICStrdup("if"); // ignore
496 LL_APPEND(ace->resources, rsrc);
498 ace->permission = 31; // R/W/U/D
503 void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
507 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in ACL provisioning operation!");
512 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received ACL provisioning results: ");
515 for (unsigned int i = 0; i < result->size(); i++)
517 convertUUIDToString(result->at(i).deviceId.id, devUuid);
518 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device %s",
519 result->at(i).res, devUuid.c_str());
527 void EnrolleeSecurity::CertProvisioningCb(PMResultList_t *result, int hasError)
531 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in Cert. provisioning operation!");
536 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received Cert. provisioning results: ");
539 for (unsigned int i = 0; i < result->size(); i++)
541 convertUUIDToString(result->at(i).deviceId.id, devUuid);
542 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device %s",
543 result->at(i).res, devUuid.c_str());
550 #endif //defined(__WITH_DTLS__) && defined(__WITH_TLS__)