[ENROLLEE] Tizen enrollee sample application build using scons command
[platform/upstream/iotivity.git] / service / easy-setup / sdk / mediator / src / EnrolleeSecurity.cpp
1 //******************************************************************\r
2 //\r
3 // Copyright 2015 Samsung Electronics All Rights Reserved.\r
4 //\r
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
6 //\r
7 // Licensed under the Apache License, Version 2.0 (the "License");\r
8 // you may not use this file except in compliance with the License.\r
9 // You may obtain a copy of the License at\r
10 //\r
11 //      http://www.apache.org/licenses/LICENSE-2.0\r
12 //\r
13 // Unless required by applicable law or agreed to in writing, software\r
14 // distributed under the License is distributed on an "AS IS" BASIS,\r
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16 // See the License for the specific language governing permissions and\r
17 // limitations under the License.\r
18 //\r
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
20 \r
21 #include "base64.h"\r
22 \r
23 #include "EnrolleeSecurity.h"\r
24 #include "oxmjustworks.h"\r
25 #include "oxmrandompin.h"\r
26 #include "RemoteEnrolleeResource.h"\r
27 #include "logger.h"\r
28 #include "ESException.h"\r
29 #include "oic_malloc.h"\r
30 #include "oic_string.h"\r
31 \r
32 namespace OIC\r
33 {\r
34     namespace Service\r
35     {\r
36         #define MAX_PERMISSION_LENGTH (5)\r
37         #define CREATE (1)\r
38         #define READ (2)\r
39         #define UPDATE (4)\r
40         #define DELETE (8)\r
41         #define NOTIFY (16)\r
42         #define DASH '-'\r
43 \r
44         //TODO : Currently discovery timeout for owned and unowned devices is fixed as 5\r
45         // The value should be accepted from the application as a parameter during ocplatform\r
46         // config call\r
47 #define ES_SEC_DISCOVERY_TIMEOUT 5\r
48 \r
49         EnrolleeSecurity::EnrolleeSecurity(\r
50         std::shared_ptr< RemoteEnrolleeResource > remoteEnrolleeResource,\r
51         std::string secDbPath)\r
52         {\r
53             m_enrolleeSecState = EnrolleeSecState::ES_SEC_UNKNOWN;\r
54             m_remoteEnrolleeResource = remoteEnrolleeResource;\r
55 \r
56             //Initializing the provisioning client stack using the db path provided by the\r
57             // application.\r
58             // Note : If the path is NULL or empty, the PDM.db should be present in the same path.\r
59             OCStackResult result = OCSecure::provisionInit(secDbPath);\r
60 \r
61             if (result != OC_STACK_OK)\r
62             {\r
63                 throw ESPlatformException(result);\r
64             }\r
65         }\r
66 \r
67         ESResult EnrolleeSecurity::registerCallbackHandler(EnrolleeSecStatusCb enrolleeSecStatusCb,\r
68                 SecurityPinCb securityPinCb, SecProvisioningDbPathCb secProvisioningDbPathCb)\r
69 \r
70         {\r
71             m_enrolleeSecStatusCb = enrolleeSecStatusCb;\r
72             m_securityPinCb = securityPinCb;\r
73             m_secProvisioningDbPathCb = secProvisioningDbPathCb;\r
74 \r
75             return ES_ERROR;\r
76         }\r
77 \r
78         std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::findEnrollee(std::string host,\r
79                 DeviceList_t &list)\r
80         {\r
81             for (unsigned int i = 0; i < list.size(); i++)\r
82             {\r
83                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,\r
84                         list[i]->getDeviceID().c_str());OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s", list[i]->getDevAddr().c_str());\r
85 \r
86                 if (list[i]->getDevAddr() == host)\r
87                 {\r
88                     return list[i];\r
89                 }\r
90             }\r
91 \r
92             return nullptr;\r
93         }\r
94 \r
95         void EnrolleeSecurity::convertUUIDToString(OicUuid_t uuid, std::string& uuidString)\r
96         {\r
97             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] =\r
98             { 0, };\r
99             uint32_t outLen = 0;\r
100             B64Result b64Ret = B64_OK;\r
101             std::ostringstream deviceId("");\r
102 \r
103             b64Ret = b64Encode(uuid.id, sizeof(uuid.id),\r
104                     base64Buff, sizeof(base64Buff), &outLen);\r
105 \r
106             if (B64_OK == b64Ret)\r
107             {\r
108                 deviceId << base64Buff;\r
109             }\r
110             uuidString =  deviceId.str();\r
111         }\r
112 \r
113         void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)\r
114         {\r
115             if (hasError)\r
116             {\r
117                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");\r
118 \r
119                 std::shared_ptr< SecProvisioningResult > securityProvisioningStatus = nullptr;\r
120                 std::string uuid;\r
121                 convertUUIDToString(result->at(0).deviceId, uuid);\r
122                 securityProvisioningStatus = std::make_shared< SecProvisioningResult >(uuid,\r
123                         ES_ERROR);\r
124 \r
125                 m_enrolleeSecStatusCb(securityProvisioningStatus);\r
126                 return;\r
127             }\r
128             else\r
129             {\r
130                 OC_LOG(DEBUG, ENROLEE_SECURITY_TAG,"Transferred Ownership successfuly for device : ");\r
131                 std::string uuid;\r
132                 convertUUIDToString(result->at(0).deviceId, uuid);\r
133                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());\r
134 \r
135                 //TODO : Decide if we have to manage the owned/unowned devices.\r
136                 //pOwnedDevList.push_back(pUnownedDevList[transferDevIdx]);\r
137                 //pUnownedDevList.erase(pUnownedDevList.begin() + transferDevIdx);\r
138 \r
139                 OC_LOG(DEBUG, ENROLEE_SECURITY_TAG,\r
140                         "Ownership transfer success success. Continuing with provisioning ACL");\r
141 \r
142                 if (provisionAcl() == ES_ERROR)\r
143                 {\r
144                     OC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in provisionAcl");\r
145                     std::shared_ptr< SecProvisioningResult > securityProvisioningStatus = nullptr;\r
146                     std::string uuid;\r
147                     convertUUIDToString(result->at(0).deviceId, uuid);\r
148                     securityProvisioningStatus = std::make_shared< SecProvisioningResult >(uuid,\r
149                             ES_ERROR);\r
150                 }\r
151 \r
152                 delete result;\r
153             }\r
154         }\r
155 \r
156         /**\r
157          * Callback function for provisioning ACL, Credentials.\r
158          *\r
159          * @param[in]    result Result list\r
160          * @param[in] hasError indicates if the result has error\r
161          */\r
162         void EnrolleeSecurity::provisionCb(OC::PMResultList_t *result, int hasError)\r
163         {\r
164             if (hasError)\r
165             {\r
166                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "provisionCb : Error in provisioning operation!");\r
167             }\r
168             else\r
169             {\r
170                 OC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "provisionCb : Received provisioning results: ");\r
171                 for (unsigned int i = 0; i < result->size(); i++)\r
172                 {\r
173                     OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);\r
174                     std::string uuid;\r
175                     convertUUIDToString(result->at(0).deviceId, uuid);\r
176 \r
177                     OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());\r
178                     std::shared_ptr< SecProvisioningResult > securityProvisioningStatus = nullptr;\r
179                     securityProvisioningStatus = std::make_shared< SecProvisioningResult >(uuid,\r
180                             ES_OK);\r
181 \r
182                     m_enrolleeSecStatusCb(securityProvisioningStatus);\r
183                     return;\r
184                 }\r
185 \r
186                 delete result;\r
187             }\r
188         }\r
189 \r
190         /**\r
191          * Calculate ACL permission from string to bit\r
192          *\r
193          * @param[in] temp_psm    Input data of ACL permission string\r
194          * @param[in,out] pms    The pointer of ACL permission value\r
195          * @return  0 on success otherwise -1.\r
196          */\r
197         int EnrolleeSecurity::CalculateAclPermission(const char *temp_pms, uint16_t *pms)\r
198         {\r
199             int i = 0;\r
200 \r
201             if (NULL == temp_pms || NULL == pms)\r
202             {\r
203                 return -1;\r
204             }\r
205             *pms = 0;\r
206             while (temp_pms[i] != '\0')\r
207             {\r
208                 switch (temp_pms[i])\r
209                 {\r
210                     case 'C':\r
211                         {\r
212                             *pms += CREATE;\r
213                             i++;\r
214                             break;\r
215                         }\r
216                     case 'R':\r
217                         {\r
218                             *pms += READ;\r
219                             i++;\r
220                             break;\r
221                         }\r
222                     case 'U':\r
223                         {\r
224                             *pms += UPDATE;\r
225                             i++;\r
226                             break;\r
227                         }\r
228                     case 'D':\r
229                         {\r
230                             *pms += DELETE;\r
231                             i++;\r
232                             break;\r
233                         }\r
234                     case 'N':\r
235                         {\r
236                             *pms += NOTIFY;\r
237                             i++;\r
238                             break;\r
239                         }\r
240                     case '_':\r
241                         {\r
242                             i++;\r
243                             break;\r
244                         }\r
245                     default:\r
246                         {\r
247                             return -1;\r
248                         }\r
249                 }\r
250             }\r
251             return 0;\r
252         }\r
253 \r
254         EasySetupState EnrolleeSecurity::performOwnershipTransfer()\r
255         {\r
256             EasySetupState ownershipStatus = DEVICE_NOT_OWNED;\r
257 \r
258             OC::DeviceList_t pUnownedDevList, pOwnedDevList;\r
259 \r
260             pOwnedDevList.clear();\r
261             pUnownedDevList.clear();\r
262 \r
263             OCStackResult result;\r
264 \r
265             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,\r
266                     pOwnedDevList);\r
267             if (result != OC_STACK_OK)\r
268             {\r
269                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");\r
270                 ownershipStatus = DEVICE_NOT_OWNED;\r
271                 //Throw exception\r
272                 throw ESPlatformException(result);\r
273                 return ownershipStatus;\r
274             }\r
275             else if (pOwnedDevList.size())\r
276             {\r
277                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",\r
278                         pOwnedDevList.size());\r
279                 std::shared_ptr< OC::OCSecureResource > ownedDevice =\r
280                         findEnrollee(\r
281                                 std::string(\r
282                                         m_remoteEnrolleeResource->m_enrolleeNWProvInfo.netAddressInfo.WIFI.ipAddress),\r
283                                 pOwnedDevList);\r
284                 if (ownedDevice)\r
285                 {\r
286                     ownershipStatus = DEVICE_OWNED;\r
287                     return ownershipStatus;\r
288                 }\r
289             }\r
290             else\r
291             {\r
292                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No owned devices found.");\r
293                 ownershipStatus = DEVICE_NOT_OWNED;\r
294             }\r
295 \r
296             result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);\r
297             if (result != OC_STACK_OK)\r
298             {\r
299                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");\r
300                 ownershipStatus = DEVICE_NOT_OWNED;\r
301                 //Throw exception\r
302                 throw ESPlatformException(result);\r
303                 return ownershipStatus;\r
304             }\r
305             else if (pUnownedDevList.size())\r
306             {\r
307                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",\r
308                         pUnownedDevList.size());\r
309 \r
310                 m_unownedDevice =\r
311                         findEnrollee(\r
312                                 m_remoteEnrolleeResource->m_enrolleeNWProvInfo.netAddressInfo.WIFI.ipAddress,\r
313                                 pUnownedDevList);\r
314                 if (m_unownedDevice)\r
315                 {\r
316                     OTMCallbackData_t justWorksCBData;\r
317                     justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;\r
318                     justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;\r
319                     justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;\r
320                     justWorksCBData.createOwnerTransferPayloadCB =\r
321                             CreateJustWorksOwnerTransferPayload;\r
322                     OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);\r
323 \r
324                     OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",\r
325                             m_unownedDevice->getDeviceID().c_str());\r
326 \r
327                     OC::ResultCallBack ownershipTransferCb = std::bind(\r
328                             &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,\r
329                             std::placeholders::_2);\r
330 \r
331                     if (m_unownedDevice->doOwnershipTransfer(ownershipTransferCb) != OC_STACK_OK)\r
332                     {\r
333                         OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "OwnershipTransferCallback is failed");\r
334                         ownershipStatus = DEVICE_NOT_OWNED;\r
335                         //Throw exception\r
336                         throw ESPlatformException(result);\r
337                     }\r
338                     ownershipStatus = DEVICE_NOT_OWNED;\r
339                 }\r
340             }\r
341             else\r
342             {\r
343                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unSecure devices found.");\r
344                 ownershipStatus = DEVICE_NOT_OWNED;\r
345 \r
346                 return ownershipStatus;\r
347             }\r
348 \r
349             return ownershipStatus;\r
350         }\r
351 \r
352         ESResult EnrolleeSecurity::createProvisiongResourceACL(OicSecAcl_t *acl)\r
353         {\r
354             //TODO : Have to accept subject id of the mediator from application during easysetup\r
355             // initialization.\r
356             char temp_id[UUID_LENGTH+1] = {"admindeviceUUID0"};\r
357             for (int i = 0, j = 0; temp_id[i] != '\0'; i++)\r
358             {\r
359                 acl->subject.id[j++] = temp_id[i];\r
360             }\r
361 \r
362             //Always resource length is 1. /oic/prov is the only resource for which needs ACL\r
363             // permission has to be set\r
364             acl->resourcesLen = 1;\r
365             acl->resources = (char **) OICCalloc(acl->resourcesLen, sizeof(char *));\r
366             if (NULL == acl->resources)\r
367             {\r
368                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while memory allocation");\r
369                 return ES_ERROR;\r
370             }\r
371 \r
372             char temp_rsc[MAX_URI_LENGTH] = {OC_RSRVD_ES_URI_PROV};\r
373 \r
374             for (size_t i = 0; i < acl->resourcesLen; i++)\r
375             {\r
376                 acl->resources[i] = OICStrdup(temp_rsc);\r
377                 if (NULL == acl->resources[i])\r
378                 {\r
379                     OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while memory allocation");\r
380                     return ES_ERROR;\r
381                 }\r
382             }\r
383             // Set Permission\r
384             char temp_pms[MAX_PERMISSION_LENGTH+1]={"CRUDN"};\r
385             int ret;\r
386             do\r
387             {\r
388                 ret = CalculateAclPermission(temp_pms, &(acl->permission));\r
389             } while (0 != ret);\r
390 \r
391             //TODO : Have to accept subject id of the mediator from application during easysetup\r
392             // initialization.\r
393             for (int i = 0, j = 0; temp_id[i] != '\0'; i++)\r
394             {\r
395                 acl->subject.id[j++] = temp_id[i];\r
396             }\r
397 \r
398             // Set Rowner\r
399             acl->ownersLen = 1;//Always resource owner is only one, which is the mediator\r
400             acl->owners = (OicUuid_t *) OICCalloc(acl->ownersLen, sizeof(OicUuid_t));\r
401             if (NULL == acl->owners)\r
402             {\r
403                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while memory allocation");\r
404                 return ES_ERROR;\r
405             }\r
406             for (size_t i = 0; i < acl->ownersLen; i++)\r
407             {\r
408                 for (int k = 0, j = 0; temp_id[k] != '\0'; k++)\r
409                 {\r
410                     acl->owners[i].id[j++] = temp_id[k];\r
411                 }\r
412             }\r
413             return ES_OK;\r
414         }\r
415 \r
416         ESResult EnrolleeSecurity::provisionAcl()\r
417         {\r
418             // TODO : Currently device uuid is hardcoded, but this id has to be obtained from the\r
419             // application\r
420             OicSecAcl_t *acl = nullptr;\r
421 \r
422             acl = (OicSecAcl_t *) OICCalloc(1, sizeof(OicSecAcl_t));\r
423             if (nullptr == acl)\r
424             {\r
425                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while memory allocation");\r
426                 return ES_ERROR;\r
427             }\r
428 \r
429             if ( createProvisiongResourceACL (acl) == ES_ERROR)\r
430             {\r
431                return ES_ERROR;\r
432             }\r
433 \r
434 \r
435             OC::ResultCallBack provisioningCb = std::bind(&EnrolleeSecurity::provisionCb, this,\r
436             std::placeholders::_1, std::placeholders::_2);\r
437 \r
438             if (m_unownedDevice->provisionACL(acl, provisioningCb) != OC_STACK_OK)\r
439             {\r
440                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "provisionACL is failed");\r
441                 return ES_ERROR;\r
442             }\r
443             return ES_OK;\r
444         }\r
445     }\r
446 }\r