Refactored structures and APIs for medaitor & Enrollee
[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 "RemoteEnrolleeResource.h"
27 #include "logger.h"
28 #include "ESException.h"
29 #include "oic_malloc.h"
30 #include "oic_string.h"
31
32 namespace OIC
33 {
34     namespace Service
35     {
36         #define MAX_PERMISSION_LENGTH (5)
37         #define CREATE (1)
38         #define READ (2)
39         #define UPDATE (4)
40         #define DELETE (8)
41         #define NOTIFY (16)
42         #define DASH '-'
43
44         //TODO : Currently discovery timeout for owned and unowned devices is fixed as 5
45         // The value should be accepted from the application as a parameter during ocplatform
46         // config call
47 #define ES_SEC_DISCOVERY_TIMEOUT 5
48
49         EnrolleeSecurity::EnrolleeSecurity(
50         std::shared_ptr< RemoteEnrolleeResource > remoteEnrolleeResource,
51         std::string secDbPath)
52         {
53             m_enrolleeSecState = EnrolleeSecState::ES_SEC_UNKNOWN;
54             m_remoteEnrolleeResource = remoteEnrolleeResource;
55
56             //Initializing the provisioning client stack using the db path provided by the
57             // application.
58             // Note : If the path is NULL or empty, the PDM.db should be present in the same path.
59             OCStackResult result = OCSecure::provisionInit(secDbPath);
60
61             if (result != OC_STACK_OK)
62             {
63                 throw ESPlatformException(result);
64             }
65         }
66
67         ESResult EnrolleeSecurity::registerCallbackHandler(EnrolleeSecStatusCb enrolleeSecStatusCb,
68                 SecurityPinCb securityPinCb, SecProvisioningDbPathCb secProvisioningDbPathCb)
69
70         {
71             m_enrolleeSecStatusCb = enrolleeSecStatusCb;
72             m_securityPinCb = securityPinCb;
73             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
74
75             return ES_ERROR;
76         }
77
78         std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::findEnrollee(std::string host,
79                 DeviceList_t &list)
80         {
81             for (unsigned int i = 0; i < list.size(); i++)
82             {
83                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,
84                         list[i]->getDeviceID().c_str());
85                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s", list[i]->getDevAddr().c_str());
86
87                 if (list[i]->getDevAddr() == host)
88                 {
89                     return list[i];
90                 }
91             }
92
93             return nullptr;
94         }
95
96         void EnrolleeSecurity::convertUUIDToString(OicUuid_t uuid, std::string& uuidString)
97         {
98             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] =
99             { 0, };
100             uint32_t outLen = 0;
101             B64Result b64Ret = B64_OK;
102             std::ostringstream deviceId("");
103
104             b64Ret = b64Encode(uuid.id, sizeof(uuid.id),
105                     base64Buff, sizeof(base64Buff), &outLen);
106
107             if (B64_OK == b64Ret)
108             {
109                 deviceId << base64Buff;
110             }
111             uuidString =  deviceId.str();
112         }
113
114         void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
115         {
116             if (hasError)
117             {
118                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
119
120                 std::shared_ptr< SecProvisioningResult > securityProvisioningStatus = nullptr;
121                 std::string uuid;
122                 convertUUIDToString(result->at(0).deviceId, uuid);
123                 securityProvisioningStatus = std::make_shared< SecProvisioningResult >(uuid,
124                         ES_ERROR);
125
126                 m_enrolleeSecStatusCb(securityProvisioningStatus);
127                 return;
128             }
129             else
130             {
131                 OC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
132                 for (unsigned int i = 0; i < result->size(); i++)
133                 {
134                     OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
135                     std::string uuid;
136                     convertUUIDToString(result->at(0).deviceId, uuid);
137
138                     OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());
139                     std::shared_ptr< SecProvisioningResult > securityProvisioningStatus = nullptr;
140                     securityProvisioningStatus = std::make_shared< SecProvisioningResult >(uuid,
141                             ES_OK);
142
143                     m_enrolleeSecStatusCb(securityProvisioningStatus);
144                     return;
145                 }
146
147                 delete result;
148             }
149         }
150
151         EasySetupState EnrolleeSecurity::performOwnershipTransfer()
152         {
153             EasySetupState ownershipStatus = DEVICE_NOT_OWNED;
154
155             OC::DeviceList_t pUnownedDevList, pOwnedDevList;
156
157             pOwnedDevList.clear();
158             pUnownedDevList.clear();
159
160             OCStackResult result;
161
162             //Developer note : Always test the mediator and enrollee applications on different devices. Running
163             // Mediator and Enrollee in same device will result in returning the same device as already owned.
164             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
165                     pOwnedDevList);
166             if (result != OC_STACK_OK)
167             {
168                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
169                 ownershipStatus = DEVICE_NOT_OWNED;
170                 //Throw exception
171                 throw ESPlatformException(result);
172                 return ownershipStatus;
173             }
174             else if (pOwnedDevList.size())
175             {
176                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
177                         pOwnedDevList.size());
178                 std::shared_ptr< OC::OCSecureResource > ownedDevice =
179                         findEnrollee(
180                                 std::string(
181                                         m_remoteEnrolleeResource->m_wifiOnboardingconn.ipAddress),
182                                 pOwnedDevList);
183                 if (ownedDevice)
184                 {
185                     ownershipStatus = DEVICE_OWNED;
186                     return ownershipStatus;
187                 }
188             }
189             else
190             {
191                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No owned devices found.");
192                 ownershipStatus = DEVICE_NOT_OWNED;
193             }
194
195             result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);
196             if (result != OC_STACK_OK)
197             {
198                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
199                 ownershipStatus = DEVICE_NOT_OWNED;
200                 //Throw exception
201                 throw ESPlatformException(result);
202                 return ownershipStatus;
203             }
204             else if (pUnownedDevList.size())
205             {
206                 OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
207                         pUnownedDevList.size());
208
209                 m_unownedDevice =
210                         findEnrollee(
211                                 m_remoteEnrolleeResource->m_wifiOnboardingconn.ipAddress,
212                                 pUnownedDevList);
213                 if (m_unownedDevice)
214                 {
215                     OTMCallbackData_t justWorksCBData;
216                     justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
217                     justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
218                     justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
219                     justWorksCBData.createOwnerTransferPayloadCB =
220                             CreateJustWorksOwnerTransferPayload;
221                     OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
222
223                     OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
224                             m_unownedDevice->getDeviceID().c_str());
225
226                     OC::ResultCallBack ownershipTransferCb = std::bind(
227                             &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
228                             std::placeholders::_2);
229
230                     if (m_unownedDevice->doOwnershipTransfer(ownershipTransferCb) != OC_STACK_OK)
231                     {
232                         OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "OwnershipTransferCallback is failed");
233                         ownershipStatus = DEVICE_NOT_OWNED;
234                         //Throw exception
235                         throw ESPlatformException(result);
236                     }
237                     ownershipStatus = DEVICE_NOT_OWNED;
238                 }
239             }
240             else
241             {
242                 OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unSecure devices found.");
243                 ownershipStatus = DEVICE_NOT_OWNED;
244
245                 return ownershipStatus;
246             }
247
248             return ownershipStatus;
249         }
250     }
251 }