Merge branch 'cloud-interface'
[platform/upstream/iotivity.git] / service / easy-setup / mediator / richsdk / src / EnrolleeSecurity.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "base64.h"
22
23 #include "EnrolleeSecurity.h"
24 #include "oxmjustworks.h"
25 #include "oxmrandompin.h"
26 #include "EnrolleeResource.h"
27 #include "logger.h"
28 #include "ESException.h"
29 #include "oic_malloc.h"
30 #include "oic_string.h"
31 #include "utlist.h"
32
33 namespace OIC
34 {
35     namespace Service
36     {
37         #define MAX_PERMISSION_LENGTH (5)
38         #define CREATE (1)
39         #define READ (2)
40         #define UPDATE (4)
41         #define DELETE (8)
42         #define NOTIFY (16)
43         #define DASH '-'
44
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
47         // config call
48         #define ES_SEC_DISCOVERY_TIMEOUT 5
49
50         EnrolleeSecurity::EnrolleeSecurity(
51             std::shared_ptr< OC::OCResource > resource,
52             const std::string secDbPath)
53         {
54             (void) secDbPath;
55             m_ocResource = resource;
56         }
57
58         void EnrolleeSecurity::registerCallbackHandler(
59             const SecurityProvStatusCb securityProvStatusCb,
60             const SecurityPinCb securityPinCb,
61             const SecProvisioningDbPathCb secProvisioningDbPathCb)
62         {
63             m_securityProvStatusCb = securityProvStatusCb;
64             m_securityPinCb = securityPinCb;
65             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
66         }
67
68         std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::getEnrollee(
69             DeviceList_t &list)
70         {
71             for (unsigned int i = 0; i < list.size(); i++)
72             {
73                 if(m_ocResource->sid() == list[i]->getDeviceID().c_str())
74                 {
75                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,
76                             list[i]->getDeviceID().c_str());
77                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s",
78                                                             list[i]->getDevAddr().c_str());
79                     return list[i];
80                 }
81             }
82             OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! DeviceList_t is NULL");
83             return NULL;
84         }
85
86         void EnrolleeSecurity::convertUUIDToString(const OicUuid_t uuid,
87                                                               std::string& uuidString)
88         {
89             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] =
90             { 0, };
91             uint32_t outLen = 0;
92             B64Result b64Ret = B64_OK;
93             std::ostringstream deviceId("");
94
95             b64Ret = b64Encode(uuid.id, sizeof(uuid.id),
96                     base64Buff, sizeof(base64Buff), &outLen);
97
98             if (B64_OK == b64Ret)
99             {
100                 deviceId << base64Buff;
101             }
102             uuidString =  deviceId.str();
103         }
104
105         void EnrolleeSecurity::convertStringToUUID(OicUuid_t& uuid,
106                                                               const std::string uuidString)
107         {
108             size_t outBufSize = B64DECODE_OUT_SAFESIZE((uuidString.length() + 1));
109             uint8_t* outKey = (uint8_t*)OICCalloc(1, outBufSize);
110             uint32_t outKeySize = 0;
111             if(NULL == outKey)
112             {
113                 OIC_LOG (ERROR, ENROLEE_SECURITY_TAG, "Failed to memoray allocation.");
114                 throw ESBadRequestException ("Failed to memoray allocation.");
115             }
116
117             if(B64_OK == b64Decode((char*)uuidString.c_str(),
118                                     uuidString.length(),
119                                     outKey,
120                                     outBufSize,
121                                     &outKeySize))
122             {
123                 memcpy(uuid.id, outKey, outKeySize);
124             }
125             else
126             {
127                 OIC_LOG (ERROR, ENROLEE_SECURITY_TAG, "Failed to base64 decoding.");
128                 throw ESBadRequestException ("Failed to base64 decoding.");
129             }
130
131             OICFree(outKey);
132         }
133
134         void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
135         {
136             if (hasError)
137             {
138                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
139
140                 std::string uuid;
141                 convertUUIDToString(result->at(0).deviceId, uuid);
142                 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
143                         std::make_shared< SecProvisioningStatus >(uuid, ES_ERROR);
144                 m_securityProvStatusCb(securityProvisioningStatus);
145                 return;
146             }
147             else
148             {
149                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
150                 for (unsigned int i = 0; i < result->size(); i++)
151                 {
152                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
153                     std::string uuid;
154                     convertUUIDToString(result->at(0).deviceId, uuid);
155
156                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());
157                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
158                             std::make_shared< SecProvisioningStatus >(uuid, ES_OK);
159                     m_securityProvStatusCb(securityProvisioningStatus);
160                     return;
161                 }
162
163                 delete result;
164             }
165         }
166
167         void EnrolleeSecurity::performOwnershipTransfer()
168         {
169             OC::DeviceList_t pUnownedDevList, pOwnedDevList;
170
171             pOwnedDevList.clear();
172             pUnownedDevList.clear();
173
174             OCStackResult result = OC_STACK_ERROR;
175
176             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
177                     pOwnedDevList);
178             if (result != OC_STACK_OK)
179             {
180                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
181                 //Throw exception
182                 throw ESPlatformException(result);
183             }
184             else if (pOwnedDevList.size())
185             {
186                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
187                         pOwnedDevList.size());
188                 std::shared_ptr< OC::OCSecureResource > ownedDevice = getEnrollee(pOwnedDevList);
189
190                 if (ownedDevice)
191                 {
192                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
193                             std::make_shared< SecProvisioningStatus >(ownedDevice->getDeviceID(), ES_OK);
194                     m_securityProvStatusCb(securityProvisioningStatus);
195                     return;
196                 }
197             }
198
199             result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);
200             if (result != OC_STACK_OK)
201             {
202                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
203                 //Throw exception
204                 throw ESPlatformException(result);
205             }
206             else if (pUnownedDevList.size())
207             {
208                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
209                         pUnownedDevList.size());
210
211                 m_unownedDevice = getEnrollee(pUnownedDevList);
212                 if (m_unownedDevice)
213                 {
214                     OTMCallbackData_t justWorksCBData;
215                     justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
216                     justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
217                     justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
218                     justWorksCBData.createOwnerTransferPayloadCB =
219                             CreateJustWorksOwnerTransferPayload;
220                     OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
221
222                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
223                             m_unownedDevice->getDeviceID().c_str());
224
225                     OC::ResultCallBack ownershipTransferCb = std::bind(
226                             &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
227                             std::placeholders::_2);
228
229                     result = m_unownedDevice->doOwnershipTransfer(ownershipTransferCb);
230                     if (result != OC_STACK_OK)
231                     {
232                         OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "OwnershipTransferCallback is failed");
233                         throw ESPlatformException(result);
234                     }
235                 }
236                 else
237                 {
238                     OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No matched unowned devices found.");
239                     throw ESException("No matched unowned devices found.");
240                 }
241             }
242             else
243             {
244                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unowned devices found.");
245                 throw ESException("No unowned devices found.");
246             }
247         }
248
249         ESResult EnrolleeSecurity::performACLProvisioningForCloudServer(std::string cloudUuid)
250         {
251             ESResult res = ESResult::ES_ERROR;
252
253             OicUuid_t uuid;
254             convertStringToUUID(uuid, cloudUuid);
255
256             // Need to discover Owned device in a given network, again
257             OC::DeviceList_t pOwnedDevList;
258             std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
259
260             pOwnedDevList.clear();
261
262             OCStackResult result;
263
264             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
265                     pOwnedDevList);
266             if (result != OC_STACK_OK)
267             {
268                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
269                 //Throw exception
270                 throw ESPlatformException(result);
271             }
272             else if (pOwnedDevList.size())
273             {
274                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
275                         pOwnedDevList.size());
276                 ownedDevice = getEnrollee(pOwnedDevList);
277
278                 if (!ownedDevice)
279                 {
280                     OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
281                     return res;
282                 }
283             }
284             else
285             {
286                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
287                 return res;
288             }
289
290             // Create Acl for Cloud Server to be provisioned to Enrollee
291             OicSecAcl_t* acl = createAcl(uuid);
292             if(!acl)
293             {
294                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
295                 return res;
296             }
297
298             OC::ResultCallBack aclProvisioningCb = std::bind(
299                             &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
300                             std::placeholders::_2);
301             // ACL provisioning to Enrollee
302             OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
303             if(OC_STACK_OK != rst)
304             {
305                 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
306                 return res;
307             }
308
309             std::unique_lock<std::mutex> lck(m_mtx);
310             m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
311
312             if(aclResult)
313             {
314                 res = ESResult::ES_OK;
315             }
316
317             return res;
318         }
319
320         std::string EnrolleeSecurity::getUUID() const
321         {
322             return m_ocResource->sid();
323         };
324
325         OicSecAcl_t* EnrolleeSecurity::createAcl(const OicUuid_t cloudUuid)
326         {
327             // allocate memory for |acl| struct
328             OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
329             if(!acl)
330             {
331                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
332                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
333             }
334             OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
335             if(!ace)
336             {
337                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
338                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
339             }
340             LL_APPEND(acl->aces, ace);
341
342             memcpy(&ace->subjectuuid, &cloudUuid, UUID_LENGTH);
343
344             OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
345             if(!rsrc)
346             {
347                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
348                 OCDeleteACLList(acl);
349                 return NULL;
350             }
351
352             char href[] = "*";
353             size_t len = strlen(href)+1;  // '1' for null termination
354             rsrc->href = (char*) OICCalloc(len, sizeof(char));
355             if(!rsrc->href)
356             {
357                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
358                 OCDeleteACLList(acl);
359                 return NULL;
360             }
361             OICStrcpy(rsrc->href, len, href);
362
363             size_t arrLen = 1;
364             rsrc->typeLen = arrLen;
365             rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
366             rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
367             rsrc->types[0] = OICStrdup("rt");   // ignore
368             rsrc->interfaces[0] = OICStrdup("if");  // ignore
369
370             LL_APPEND(ace->resources, rsrc);
371
372             ace->permission = 31;   // R/W/U/D
373
374             return acl;
375         }
376
377         void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
378         {
379             if (hasError)
380             {
381                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in provisioning operation!");
382                aclResult = false;
383             }
384             else
385             {
386                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
387
388                std::string devUuid;
389                for (unsigned int i = 0; i < result->size(); i++)
390                {
391                    convertUUIDToString(result->at(i).deviceId, devUuid);
392                    OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d  for device %s",
393                                                            result->at(i).res, devUuid.c_str());
394                }
395                delete result;
396                aclResult = true;
397             }
398             m_cond.notify_all();
399         }
400     }
401 }