Add an API to provision ACL of cloud server
[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         std::string secDbPath)
53         {
54             (void) secDbPath;
55             m_ocResource = resource;
56         }
57
58         void EnrolleeSecurity::registerCallbackHandler(SecurityProvStatusCb securityProvStatusCb,
59                 SecurityPinCb securityPinCb, SecProvisioningDbPathCb secProvisioningDbPathCb)
60         {
61             m_securityProvStatusCb = securityProvStatusCb;
62             m_securityPinCb = securityPinCb;
63             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
64         }
65
66         std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::getEnrollee(DeviceList_t &list)
67         {
68             for (unsigned int i = 0; i < list.size(); i++)
69             {
70                 if(m_ocResource->sid() == list[i]->getDeviceID().c_str())
71                 {
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());
75                     return list[i];
76                 }
77                 //Always return the first element of the unOwned devices. This is considering that Mediator is
78                 // always connected with only one Enrollee for which ownership transfer is being performed.
79                 // Incase of multiple Enrollee devices connected to the Mediator via any OnBoarding method (SoftAp
80                 // for example), the Enrollee devices will be provisioned in the first come first serve basis in the order
81                 // returned by the security layer.
82
83             }
84             OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! DeviceList_t is NULL");
85             return NULL;
86         }
87
88         void EnrolleeSecurity::convertUUIDToString(OicUuid_t uuid, std::string& uuidString)
89         {
90             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] =
91             { 0, };
92             uint32_t outLen = 0;
93             B64Result b64Ret = B64_OK;
94             std::ostringstream deviceId("");
95
96             b64Ret = b64Encode(uuid.id, sizeof(uuid.id),
97                     base64Buff, sizeof(base64Buff), &outLen);
98
99             if (B64_OK == b64Ret)
100             {
101                 deviceId << base64Buff;
102             }
103             uuidString =  deviceId.str();
104         }
105
106         void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
107         {
108             if (hasError)
109             {
110                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
111
112                 std::string uuid;
113                 convertUUIDToString(result->at(0).deviceId, uuid);
114                 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
115                         std::make_shared< SecProvisioningStatus >(uuid, ES_ERROR);
116                 m_securityProvStatusCb(securityProvisioningStatus);
117                 return;
118             }
119             else
120             {
121                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
122                 for (unsigned int i = 0; i < result->size(); i++)
123                 {
124                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
125                     std::string uuid;
126                     convertUUIDToString(result->at(0).deviceId, uuid);
127
128                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());
129                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
130                             std::make_shared< SecProvisioningStatus >(uuid, ES_OK);
131                     m_securityProvStatusCb(securityProvisioningStatus);
132                     return;
133                 }
134
135                 delete result;
136             }
137         }
138
139         void EnrolleeSecurity::performOwnershipTransfer()
140         {
141             OC::DeviceList_t pUnownedDevList, pOwnedDevList;
142
143             pOwnedDevList.clear();
144             pUnownedDevList.clear();
145
146             OCStackResult result;
147             /*
148             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
149                     pOwnedDevList);
150             if (result != OC_STACK_OK)
151             {
152                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
153                 //Throw exception
154                 throw ESPlatformException(result);
155             }
156             else if (pOwnedDevList.size())
157             {
158                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
159                         pOwnedDevList.size());
160                 std::shared_ptr< OC::OCSecureResource > ownedDevice = getEnrollee(pOwnedDevList);
161
162                 if (ownedDevice)
163                 {
164                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
165                             std::make_shared< SecProvisioningStatus >(ownedDevice->getDeviceID(), ES_OK);
166                     m_securityProvStatusCb(securityProvisioningStatus);
167                     return;
168                 }
169             }
170             */
171             result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);
172             if (result != OC_STACK_OK)
173             {
174                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
175                 //Throw exception
176                 throw ESPlatformException(result);
177             }
178             else if (pUnownedDevList.size())
179             {
180                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
181                         pUnownedDevList.size());
182
183                 m_unownedDevice = getEnrollee(pUnownedDevList);
184                 if (m_unownedDevice)
185                 {
186                     OTMCallbackData_t justWorksCBData;
187                     justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
188                     justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
189                     justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
190                     justWorksCBData.createOwnerTransferPayloadCB =
191                             CreateJustWorksOwnerTransferPayload;
192                     OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
193
194                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
195                             m_unownedDevice->getDeviceID().c_str());
196
197                     OC::ResultCallBack ownershipTransferCb = std::bind(
198                             &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
199                             std::placeholders::_2);
200
201                     result = m_unownedDevice->doOwnershipTransfer(ownershipTransferCb);
202                     if (result != OC_STACK_OK)
203                     {
204                         OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "OwnershipTransferCallback is failed");
205                         throw ESPlatformException(result);
206                     }
207                 }
208             }
209             else
210             {
211                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unOwned devices found.");
212                 throw ESException("No unOwned devices found.");
213             }
214         }
215
216         void EnrolleeSecurity::performACLProvisioningForCloudServer(OicUuid_t serverUuid)
217         {
218             // Need to discover Owned device in a given network, again
219             OC::DeviceList_t pOwnedDevList;
220             std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
221
222             pOwnedDevList.clear();
223
224             OCStackResult result;
225
226             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
227                     pOwnedDevList);
228             if (result != OC_STACK_OK)
229             {
230                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
231                 //Throw exception
232                 throw ESPlatformException(result);
233             }
234             else if (pOwnedDevList.size())
235             {
236                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
237                         pOwnedDevList.size());
238                 ownedDevice = getEnrollee(pOwnedDevList);
239
240                 if (!ownedDevice)
241                 {
242                     OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
243                     return;
244                 }
245             }
246             else
247             {
248                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
249                 return;
250             }
251
252             // Create Acl for Cloud Server to be provisioned to Enrollee
253             OicSecAcl_t* acl = createAcl(serverUuid);
254             if(!acl)
255             {
256                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
257                 return;
258             }
259
260             OC::ResultCallBack aclProvisioningCb = std::bind(
261                             &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
262                             std::placeholders::_2);
263             // ACL provisioning to Enrollee
264             OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
265             if(OC_STACK_OK != rst)
266             {
267                 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
268                 return;
269             }
270         }
271
272         OicSecAcl_t* EnrolleeSecurity::createAcl(OicUuid_t serverUuid)
273         {
274             // allocate memory for |acl| struct
275             OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
276             if(!acl)
277             {
278                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
279                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
280             }
281             OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
282             if(!ace)
283             {
284                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
285                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
286             }
287             LL_APPEND(acl->aces, ace);
288
289             memcpy(&ace->subjectuuid, &serverUuid, UUID_LENGTH);
290
291             OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
292             if(!rsrc)
293             {
294                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
295                 OCDeleteACLList(acl);
296                 return NULL;
297             }
298
299             char href[] = "*";
300             size_t len = strlen(href)+1;  // '1' for null termination
301             rsrc->href = (char*) OICCalloc(len, sizeof(char));
302             if(!rsrc)
303             {
304                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
305                 OCDeleteACLList(acl);
306                 return NULL;
307             }
308             OICStrcpy(rsrc->href, len, href);
309
310             int arrLen = 1;
311             rsrc->typeLen = arrLen;
312             rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
313             rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
314             rsrc->types[0] = OICStrdup("rt");   // ignore
315             rsrc->interfaces[0] = OICStrdup("if");  // ignore
316
317             LL_APPEND(ace->resources, rsrc);
318
319             ace->permission = 31;   // R/W/U/D
320
321             return acl;
322         }
323
324         void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
325         {
326             (void) result;
327             (void) hasError;
328         }
329     }
330 }