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"
38 #define MAX_PERMISSION_LENGTH (5)
45 #define DISCOVERY_TIMEOUT (10)
47 //TODO : Currently discovery timeout for owned and unowned devices is fixed as 5
48 // The value should be accepted from the application as a parameter during ocplatform
50 #define ES_SEC_DISCOVERY_TIMEOUT 5
52 EnrolleeSecurity::EnrolleeSecurity(
53 std::shared_ptr< OC::OCResource > resource,
54 const std::string secDbPath)
57 m_ocResource = resource;
60 void EnrolleeSecurity::registerCallbackHandler(
61 const SecurityProvStatusCb securityProvStatusCb,
62 const SecurityPinCb securityPinCb,
63 const SecProvisioningDbPathCb secProvisioningDbPathCb)
65 m_securityProvStatusCb = securityProvStatusCb;
66 m_securityPinCb = securityPinCb;
67 m_secProvisioningDbPathCb = secProvisioningDbPathCb;
70 std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::findEnrolleeSecurityResource(
73 for (unsigned int i = 0; i < list.size(); i++)
75 if(m_ocResource->sid() == list[i]->getDeviceID().c_str())
77 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,
78 list[i]->getDeviceID().c_str());
79 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s",
80 list[i]->getDevAddr().c_str());
84 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! DeviceList_t is NULL");
88 void EnrolleeSecurity::convertUUIDToString(const uint8_t uuid[UUID_SIZE],
89 std::string& uuidString)
91 char uuidArray[UUID_STRING_SIZE] = {'\0',};
92 int ret = snprintf(uuidArray, UUID_STRING_SIZE,
93 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
94 uuid[0], uuid[1], uuid[2], uuid[3],
95 uuid[4], uuid[5], uuid[6], uuid[7],
96 uuid[8], uuid[9], uuid[10], uuid[11],
97 uuid[12], uuid[13], uuid[14], uuid[15]
100 if (ret != UUID_STRING_SIZE - 1)
105 uuidString = uuidArray;
108 void EnrolleeSecurity::convertStringToUUID(OicUuid_t& uuid,
109 const std::string uuidString)
111 size_t outBufSize = B64DECODE_OUT_SAFESIZE((uuidString.length() + 1));
112 uint8_t* outKey = (uint8_t*)OICCalloc(1, outBufSize);
113 uint32_t outKeySize = 0;
116 OIC_LOG (ERROR, ENROLEE_SECURITY_TAG, "Failed to memoray allocation.");
117 throw ESBadRequestException ("Failed to memoray allocation.");
120 if(B64_OK == b64Decode((char*)uuidString.c_str(),
126 memcpy(uuid.id, outKey, outKeySize);
130 OIC_LOG (ERROR, ENROLEE_SECURITY_TAG, "Failed to base64 decoding.");
131 throw ESBadRequestException ("Failed to base64 decoding.");
137 void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
141 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
144 convertUUIDToString(result->at(0).deviceId.id, uuid);
145 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
146 std::make_shared< SecProvisioningStatus >(uuid, ES_ERROR);
147 m_securityProvStatusCb(securityProvisioningStatus);
152 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
153 for (unsigned int i = 0; i < result->size(); i++)
155 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
157 convertUUIDToString(result->at(0).deviceId.id, uuid);
159 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());
160 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
161 std::make_shared< SecProvisioningStatus >(uuid, ES_OK);
162 m_securityProvStatusCb(securityProvisioningStatus);
170 void EnrolleeSecurity::provisionOwnership()
172 OC::DeviceList_t pUnownedDevList, pOwnedDevList;
174 pOwnedDevList.clear();
175 pUnownedDevList.clear();
177 OCStackResult result = OC_STACK_ERROR;
179 result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
181 if (result != OC_STACK_OK)
183 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
185 throw ESPlatformException(result);
187 else if (pOwnedDevList.size())
189 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
190 pOwnedDevList.size());
191 std::shared_ptr< OC::OCSecureResource > ownedDevice =
192 findEnrolleeSecurityResource(pOwnedDevList);
196 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
197 std::make_shared< SecProvisioningStatus >(ownedDevice->getDeviceID(), ES_OK);
198 m_securityProvStatusCb(securityProvisioningStatus);
203 result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);
204 if (result != OC_STACK_OK)
206 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
208 throw ESPlatformException(result);
210 else if (pUnownedDevList.size())
212 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
213 pUnownedDevList.size());
215 m_unownedDevice = findEnrolleeSecurityResource(pUnownedDevList);
218 if(isOwnedDeviceRegisteredInSVRDB())
220 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
221 "Found Unowned device's DevID at DB of ownedDevices list");
223 OC::ResultCallBack removeDeviceWithUuidCB = std::bind(
224 &EnrolleeSecurity::removeDeviceWithUuidCB,
225 this, std::placeholders::_1, std::placeholders::_2);
227 OCSecure::removeDeviceWithUuid(DISCOVERY_TIMEOUT,
229 removeDeviceWithUuidCB);
233 performOwnershipTransfer();
238 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No matched unowned devices found.");
239 throw ESException("No matched unowned devices found.");
244 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unowned devices found.");
245 throw ESException("No unowned devices found.");
249 void EnrolleeSecurity::performOwnershipTransfer()
251 OCStackResult result = OC_STACK_ERROR;
253 OTMCallbackData_t justWorksCBData;
254 justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
255 justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
256 justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
257 justWorksCBData.createOwnerTransferPayloadCB =
258 CreateJustWorksOwnerTransferPayload;
259 OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
261 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
262 m_unownedDevice->getDeviceID().c_str());
264 OC::ResultCallBack ownershipTransferCb = std::bind(
265 &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
266 std::placeholders::_2);
268 result = m_unownedDevice->doOwnershipTransfer(ownershipTransferCb);
269 if (result != OC_STACK_OK)
271 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "doOwnershipTransfer is failed");
272 throw ESPlatformException(result);
276 void EnrolleeSecurity::removeDeviceWithUuidCB(OC::PMResultList_t *result, int hasError)
280 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in removeDeviceWithUuid operation!");
281 throw ESException("removeDeviceWithUuid Error");
286 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
288 for (unsigned int i = 0; i < result->size(); i++)
291 convertUUIDToString(result->at(i).deviceId.id, uuid);
293 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
294 "Result is = %d for device %s", result->at(i).res, uuid.c_str());
296 performOwnershipTransfer();
300 bool EnrolleeSecurity::isOwnedDeviceRegisteredInSVRDB()
302 OCStackResult res = OC_STACK_ERROR;
304 OCUuidList_t *uuidList = NULL;
305 size_t numOfDevices = 0;
307 res = PDMGetOwnedDevices(&uuidList, &numOfDevices);
308 if (OC_STACK_OK != res)
310 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while getting info from DB");
314 OCUuidList_t *pUuidList = uuidList;
319 convertUUIDToString(pUuidList->dev.id, uuid);
320 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
321 "m_ocResource->sid(): %s, cur DB UUID %s",
322 m_ocResource->sid().c_str(), uuid.c_str());
323 if(m_ocResource->sid() == uuid.c_str())
327 pUuidList = pUuidList->next;
333 std::string EnrolleeSecurity::getUUID() const
335 return m_ocResource->sid();
338 #if defined(__WITH_DTLS__) && defined(__WITH_TLS__)
339 void EnrolleeSecurity::provisionSecurityForCloudServer(
340 std::string cloudUuid, int credId)
342 // Need to discover Owned device in a given network, again
343 OC::DeviceList_t pOwnedDevList;
344 std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
346 pOwnedDevList.clear();
348 OCStackResult result;
350 result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
352 if (result != OC_STACK_OK)
354 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
356 throw ESPlatformException(result);
358 else if (pOwnedDevList.size())
360 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
361 pOwnedDevList.size());
362 ownedDevice = findEnrolleeSecurityResource(pOwnedDevList);
366 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found matched owned device.");
367 throw ESException("Not found matched owned device.");
372 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
373 throw ESException("Not found owned devices.");
376 if(!cloudUuid.empty()
377 && performACLProvisioningForCloudServer(ownedDevice, cloudUuid) != ESResult::ES_OK)
379 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performACLProvisioningForCloudServer");
380 throw ESException("error performACLProvisioningForCloudServer");
384 && performCertProvisioningForCloudServer(ownedDevice, credId) != ESResult::ES_OK)
386 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performCertProvisioningForCloudServer");
387 throw ESException("error performCertProvisioningForCloudServer");
391 ESResult EnrolleeSecurity::performCertProvisioningForCloudServer(
392 std::shared_ptr< OC::OCSecureResource > ownedDevice, int credId)
394 ESResult res = ESResult::ES_ERROR;
398 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
401 OC::ResultCallBack CertProvisioningCb = std::bind(
402 &EnrolleeSecurity::CertProvisioningCb, this, std::placeholders::_1,
403 std::placeholders::_2);
404 OCStackResult rst = ownedDevice->provisionTrustCertChain(SIGNED_ASYMMETRIC_KEY,
405 static_cast<uint16_t>(credId),
407 if(OC_STACK_OK != rst)
409 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "provisionTrustCertChain error: %d", rst);
413 std::unique_lock<std::mutex> lck(m_mtx);
414 m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
418 res = ESResult::ES_OK;
424 ESResult EnrolleeSecurity::performACLProvisioningForCloudServer(
425 std::shared_ptr< OC::OCSecureResource > ownedDevice, std::string& cloudUuid)
427 ESResult res = ESResult::ES_ERROR;
431 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
434 if(cloudUuid.empty())
436 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
441 convertStringToUUID(uuid, cloudUuid);
443 // Create Acl for Cloud Server to be provisioned to Enrollee
444 OicSecAcl_t* acl = createAcl(uuid);
447 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
451 OC::ResultCallBack aclProvisioningCb = std::bind(
452 &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
453 std::placeholders::_2);
454 // ACL provisioning to Enrollee
455 OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
456 if(OC_STACK_OK != rst)
458 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
462 std::unique_lock<std::mutex> lck(m_mtx);
463 m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
467 res = ESResult::ES_OK;
473 OicSecAcl_t* EnrolleeSecurity::createAcl(const OicUuid_t cloudUuid)
475 // allocate memory for |acl| struct
476 OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
479 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
480 return NULL; // not need to 'goto' |ERROR| before allocating |acl|
482 OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
485 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
486 return NULL; // not need to 'goto' |ERROR| before allocating |acl|
488 LL_APPEND(acl->aces, ace);
490 memcpy(&ace->subjectuuid, &cloudUuid, UUID_LENGTH);
492 OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
495 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
496 OCDeleteACLList(acl);
501 size_t len = strlen(href)+1; // '1' for null termination
502 rsrc->href = (char*) OICCalloc(len, sizeof(char));
505 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
506 OCDeleteACLList(acl);
509 OICStrcpy(rsrc->href, len, href);
512 rsrc->typeLen = arrLen;
513 rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
514 rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
515 rsrc->types[0] = OICStrdup("rt"); // ignore
516 rsrc->interfaces[0] = OICStrdup("if"); // ignore
518 LL_APPEND(ace->resources, rsrc);
520 ace->permission = 31; // R/W/U/D
525 void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
529 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in ACL provisioning operation!");
534 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received ACL provisioning results: ");
537 for (unsigned int i = 0; i < result->size(); i++)
539 convertUUIDToString(result->at(i).deviceId.id, devUuid);
540 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device %s",
541 result->at(i).res, devUuid.c_str());
549 void EnrolleeSecurity::CertProvisioningCb(PMResultList_t *result, int hasError)
553 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in Cert. provisioning operation!");
558 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received Cert. provisioning results: ");
561 for (unsigned int i = 0; i < result->size(); i++)
563 convertUUIDToString(result->at(i).deviceId.id, devUuid);
564 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device %s",
565 result->at(i).res, devUuid.c_str());
572 #endif //defined(__WITH_DTLS__) && defined(__WITH_TLS__)