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 "oic_string.h"
37 #define MAX_PERMISSION_LENGTH (5)
45 //TODO : Currently discovery timeout for owned and unowned devices is fixed as 5
46 // The value should be accepted from the application as a parameter during ocplatform
48 #define ES_SEC_DISCOVERY_TIMEOUT 5
50 EnrolleeSecurity::EnrolleeSecurity(
51 std::shared_ptr< OC::OCResource > resource,
52 std::string secDbPath)
55 m_ocResource = resource;
58 void EnrolleeSecurity::registerCallbackHandler(SecurityProvStatusCb securityProvStatusCb,
59 SecurityPinCb securityPinCb, SecProvisioningDbPathCb secProvisioningDbPathCb)
61 m_securityProvStatusCb = securityProvStatusCb;
62 m_securityPinCb = securityPinCb;
63 m_secProvisioningDbPathCb = secProvisioningDbPathCb;
66 std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::getEnrollee(DeviceList_t &list)
68 for (unsigned int i = 0; i < list.size(); i++)
70 if(m_ocResource->sid() == list[i]->getDeviceID().c_str())
72 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,
73 list[i]->getDeviceID().c_str());
74 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s", list[i]->getDevAddr().c_str());
78 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! DeviceList_t is NULL");
82 void EnrolleeSecurity::convertUUIDToString(OicUuid_t uuid, std::string& uuidString)
84 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] =
87 B64Result b64Ret = B64_OK;
88 std::ostringstream deviceId("");
90 b64Ret = b64Encode(uuid.id, sizeof(uuid.id),
91 base64Buff, sizeof(base64Buff), &outLen);
95 deviceId << base64Buff;
97 uuidString = deviceId.str();
100 void EnrolleeSecurity::convertStringToUUID(OicUuid_t& uuid, std::string uuidString)
102 size_t outBufSize = B64DECODE_OUT_SAFESIZE((uuidString.length() + 1));
103 uint8_t* outKey = (uint8_t*)OICCalloc(1, outBufSize);
104 uint32_t outKeySize = 0;
107 OIC_LOG (ERROR, ENROLEE_SECURITY_TAG, "Failed to memoray allocation.");
108 throw ESBadRequestException ("Failed to memoray allocation.");
111 if(B64_OK == b64Decode((char*)uuidString.c_str(),
117 memcpy(uuid.id, outKey, outKeySize);
121 OIC_LOG (ERROR, ENROLEE_SECURITY_TAG, "Failed to base64 decoding.");
122 throw ESBadRequestException ("Failed to base64 decoding.");
128 void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
132 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
135 convertUUIDToString(result->at(0).deviceId, uuid);
136 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
137 std::make_shared< SecProvisioningStatus >(uuid, ES_ERROR);
138 m_securityProvStatusCb(securityProvisioningStatus);
143 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
144 for (unsigned int i = 0; i < result->size(); i++)
146 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
148 convertUUIDToString(result->at(0).deviceId, uuid);
150 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());
151 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
152 std::make_shared< SecProvisioningStatus >(uuid, ES_OK);
153 m_securityProvStatusCb(securityProvisioningStatus);
161 void EnrolleeSecurity::performOwnershipTransfer()
163 OC::DeviceList_t pUnownedDevList, pOwnedDevList;
165 pOwnedDevList.clear();
166 pUnownedDevList.clear();
168 OCStackResult result = OC_STACK_ERROR;
170 result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
172 if (result != OC_STACK_OK)
174 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
176 throw ESPlatformException(result);
178 else if (pOwnedDevList.size())
180 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
181 pOwnedDevList.size());
182 std::shared_ptr< OC::OCSecureResource > ownedDevice = getEnrollee(pOwnedDevList);
186 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
187 std::make_shared< SecProvisioningStatus >(ownedDevice->getDeviceID(), ES_OK);
188 m_securityProvStatusCb(securityProvisioningStatus);
193 result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);
194 if (result != OC_STACK_OK)
196 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
198 throw ESPlatformException(result);
200 else if (pUnownedDevList.size())
202 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
203 pUnownedDevList.size());
205 m_unownedDevice = getEnrollee(pUnownedDevList);
208 OTMCallbackData_t justWorksCBData;
209 justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
210 justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
211 justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
212 justWorksCBData.createOwnerTransferPayloadCB =
213 CreateJustWorksOwnerTransferPayload;
214 OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
216 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
217 m_unownedDevice->getDeviceID().c_str());
219 OC::ResultCallBack ownershipTransferCb = std::bind(
220 &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
221 std::placeholders::_2);
223 result = m_unownedDevice->doOwnershipTransfer(ownershipTransferCb);
224 if (result != OC_STACK_OK)
226 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "OwnershipTransferCallback is failed");
227 throw ESPlatformException(result);
232 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No matched unowned devices found.");
233 throw ESException("No matched unowned devices found.");
238 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unowned devices found.");
239 throw ESException("No unowned devices found.");
243 ESResult EnrolleeSecurity::performACLProvisioningForCloudServer(std::string cloudUuid)
245 ESResult res = ESResult::ES_ERROR;
248 convertStringToUUID(uuid, cloudUuid);
250 // Need to discover Owned device in a given network, again
251 OC::DeviceList_t pOwnedDevList;
252 std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
254 pOwnedDevList.clear();
256 OCStackResult result;
258 result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
260 if (result != OC_STACK_OK)
262 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
264 throw ESPlatformException(result);
266 else if (pOwnedDevList.size())
268 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
269 pOwnedDevList.size());
270 ownedDevice = getEnrollee(pOwnedDevList);
274 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
280 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
284 // Create Acl for Cloud Server to be provisioned to Enrollee
285 OicSecAcl_t* acl = createAcl(uuid);
288 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
292 OC::ResultCallBack aclProvisioningCb = std::bind(
293 &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
294 std::placeholders::_2);
295 // ACL provisioning to Enrollee
296 OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
297 if(OC_STACK_OK != rst)
299 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
303 std::unique_lock<std::mutex> lck(m_mtx);
304 m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
308 res = ESResult::ES_OK;
314 std::string EnrolleeSecurity::getUUID() const
316 return m_ocResource->sid();
319 OicSecAcl_t* EnrolleeSecurity::createAcl(OicUuid_t cloudUuid)
321 // allocate memory for |acl| struct
322 OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
325 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
326 return NULL; // not need to 'goto' |ERROR| before allocating |acl|
328 OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
331 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
332 return NULL; // not need to 'goto' |ERROR| before allocating |acl|
334 LL_APPEND(acl->aces, ace);
336 memcpy(&ace->subjectuuid, &cloudUuid, UUID_LENGTH);
338 OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
341 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
342 OCDeleteACLList(acl);
347 size_t len = strlen(href)+1; // '1' for null termination
348 rsrc->href = (char*) OICCalloc(len, sizeof(char));
351 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
352 OCDeleteACLList(acl);
355 OICStrcpy(rsrc->href, len, href);
358 rsrc->typeLen = arrLen;
359 rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
360 rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
361 rsrc->types[0] = OICStrdup("rt"); // ignore
362 rsrc->interfaces[0] = OICStrdup("if"); // ignore
364 LL_APPEND(ace->resources, rsrc);
366 ace->permission = 31; // R/W/U/D
371 void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
375 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in provisioning operation!");
380 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
383 for (unsigned int i = 0; i < result->size(); i++)
385 convertUUIDToString(result->at(i).deviceId, devUuid);
386 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device %s",
387 result->at(i).res, devUuid.c_str());