Fix a condition to filter out a wrong cred ID
[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 "provisioningdatabasemanager.h"
31 #include "oic_string.h"
32 #include "utlist.h"
33 #include "srmutility.h"
34
35 namespace OIC
36 {
37     namespace Service
38     {
39         #define MAX_PERMISSION_LENGTH (5)
40         #define CREATE (1)
41         #define READ (2)
42         #define UPDATE (4)
43         #define DELETE (8)
44         #define NOTIFY (16)
45         #define DASH '-'
46         #define DISCOVERY_TIMEOUT (10)
47
48         //TODO : Currently discovery timeout for owned and unowned devices is fixed as 5
49         // The value should be accepted from the application as a parameter during ocplatform
50         // config call
51         #define ES_SEC_DISCOVERY_TIMEOUT 5
52
53         EnrolleeSecurity::EnrolleeSecurity(
54             std::shared_ptr< OC::OCResource > resource,
55             const std::string secDbPath)
56         {
57             (void) secDbPath;
58             m_ocResource = resource;
59         }
60
61         void EnrolleeSecurity::registerCallbackHandler(
62             const SecurityProvStatusCb securityProvStatusCb,
63             const SecurityPinCb securityPinCb,
64             const SecProvisioningDbPathCb secProvisioningDbPathCb)
65         {
66             m_securityProvStatusCb = securityProvStatusCb;
67             m_securityPinCb = securityPinCb;
68             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
69         }
70
71         std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::findEnrolleeSecurityResource(
72             DeviceList_t &list)
73         {
74             for (unsigned int i = 0; i < list.size(); i++)
75             {
76                 if(m_ocResource->sid() == list[i]->getDeviceID().c_str())
77                 {
78                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,
79                             list[i]->getDeviceID().c_str());
80                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s",
81                                                             list[i]->getDevAddr().c_str());
82                     return list[i];
83                 }
84             }
85             OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! DeviceList_t is NULL");
86             return NULL;
87         }
88
89         void EnrolleeSecurity::convertUUIDToString(const uint8_t uuid[UUID_SIZE],
90                                                               std::string& uuidString)
91         {
92             char uuidArray[UUID_STRING_SIZE] = {'\0',};
93             int ret = snprintf(uuidArray, UUID_STRING_SIZE,
94                     "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
95                     uuid[0], uuid[1], uuid[2], uuid[3],
96                     uuid[4], uuid[5], uuid[6], uuid[7],
97                     uuid[8], uuid[9], uuid[10], uuid[11],
98                     uuid[12], uuid[13], uuid[14], uuid[15]
99                     );
100
101             if (ret != UUID_STRING_SIZE - 1)
102             {
103                 return;
104             }
105
106             uuidString = uuidArray;
107         }
108
109         void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
110         {
111             if (hasError)
112             {
113                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
114
115                 std::string uuid;
116                 convertUUIDToString(result->at(0).deviceId.id, uuid);
117                 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
118                         std::make_shared< SecProvisioningStatus >(uuid, ES_ERROR);
119                 m_securityProvStatusCb(securityProvisioningStatus);
120                 return;
121             }
122             else
123             {
124                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
125                 for (unsigned int i = 0; i < result->size(); i++)
126                 {
127                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
128                     std::string uuid;
129                     convertUUIDToString(result->at(0).deviceId.id, uuid);
130
131                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",uuid.c_str());
132                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
133                             std::make_shared< SecProvisioningStatus >(uuid, ES_OK);
134                     m_securityProvStatusCb(securityProvisioningStatus);
135                     return;
136                 }
137
138                 delete result;
139             }
140         }
141
142         void EnrolleeSecurity::provisionOwnership()
143         {
144             OC::DeviceList_t pUnownedDevList, pOwnedDevList;
145
146             pOwnedDevList.clear();
147             pUnownedDevList.clear();
148
149             OCStackResult result = OC_STACK_ERROR;
150
151             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
152                     pOwnedDevList);
153             if (result != OC_STACK_OK)
154             {
155                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
156                 //Throw exception
157                 throw ESPlatformException(result);
158             }
159             else if (pOwnedDevList.size())
160             {
161                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
162                         pOwnedDevList.size());
163                 std::shared_ptr< OC::OCSecureResource > ownedDevice =
164                     findEnrolleeSecurityResource(pOwnedDevList);
165
166                 if (ownedDevice)
167                 {
168                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
169                             std::make_shared< SecProvisioningStatus >(ownedDevice->getDeviceID(), ES_OK);
170                     m_securityProvStatusCb(securityProvisioningStatus);
171                     return;
172                 }
173             }
174
175             result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT, pUnownedDevList);
176             if (result != OC_STACK_OK)
177             {
178                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
179                 //Throw exception
180                 throw ESPlatformException(result);
181             }
182             else if (pUnownedDevList.size())
183             {
184                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
185                         pUnownedDevList.size());
186
187                 m_unownedDevice = findEnrolleeSecurityResource(pUnownedDevList);
188                 if (m_unownedDevice)
189                 {
190                     if(isOwnedDeviceRegisteredInSVRDB())
191                     {
192                         OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
193                             "Found Unowned device's DevID at DB of ownedDevices list");
194
195                         OC::ResultCallBack removeDeviceWithUuidCB = std::bind(
196                                 &EnrolleeSecurity::removeDeviceWithUuidCB,
197                                 this, std::placeholders::_1, std::placeholders::_2);
198
199                         OCSecure::removeDeviceWithUuid(DISCOVERY_TIMEOUT,
200                                                        m_ocResource->sid(),
201                                                        removeDeviceWithUuidCB);
202                     }
203                     else
204                     {
205                         performOwnershipTransfer();
206                     }
207                 }
208                 else
209                 {
210                     OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No matched unowned devices found.");
211                     throw ESException("No matched unowned devices found.");
212                 }
213             }
214             else
215             {
216                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unowned devices found.");
217                 throw ESException("No unowned devices found.");
218             }
219         }
220
221         void EnrolleeSecurity::performOwnershipTransfer()
222         {
223             OCStackResult result = OC_STACK_ERROR;
224
225             OTMCallbackData_t justWorksCBData;
226             justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
227             justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
228             justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
229             justWorksCBData.createOwnerTransferPayloadCB =
230                     CreateJustWorksOwnerTransferPayload;
231             OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
232
233             OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
234                     m_unownedDevice->getDeviceID().c_str());
235
236             OC::ResultCallBack ownershipTransferCb = std::bind(
237                     &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
238                     std::placeholders::_2);
239
240             result = m_unownedDevice->doOwnershipTransfer(ownershipTransferCb);
241             if (result != OC_STACK_OK)
242             {
243                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "doOwnershipTransfer is failed");
244                 throw ESPlatformException(result);
245             }
246         }
247
248         void EnrolleeSecurity::removeDeviceWithUuidCB(OC::PMResultList_t *result, int hasError)
249         {
250             if (hasError)
251             {
252                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in removeDeviceWithUuid operation!");
253                throw ESException("removeDeviceWithUuid Error");
254             }
255
256             else
257             {
258                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
259
260                for (unsigned int i = 0; i < result->size(); i++)
261                {
262                     std::string uuid;
263                     convertUUIDToString(result->at(i).deviceId.id, uuid);
264
265                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
266                         "Result is = %d for device %s",  result->at(i).res, uuid.c_str());
267                }
268                performOwnershipTransfer();
269             }
270         }
271
272         bool EnrolleeSecurity::isOwnedDeviceRegisteredInSVRDB()
273         {
274             OCStackResult res = OC_STACK_ERROR;
275
276             OCUuidList_t *uuidList = NULL;
277             size_t numOfDevices = 0;
278
279             res = PDMGetOwnedDevices(&uuidList, &numOfDevices);
280             if (OC_STACK_OK != res)
281             {
282                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while getting info from DB");
283                 return false;
284             }
285
286             OCUuidList_t *pUuidList = uuidList;
287
288             while (pUuidList)
289             {
290                 std::string uuid;
291                 convertUUIDToString(pUuidList->dev.id, uuid);
292                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
293                     "m_ocResource->sid(): %s, cur DB UUID %s",
294                     m_ocResource->sid().c_str(), uuid.c_str());
295                 if(m_ocResource->sid() == uuid.c_str())
296                 {
297                     return true;
298                 }
299                 pUuidList = pUuidList->next;
300             }
301             return false;
302         }
303
304
305         std::string EnrolleeSecurity::getUUID() const
306         {
307             return m_ocResource->sid();
308         };
309
310 #if defined(__WITH_DTLS__) && defined(__WITH_TLS__)
311         void EnrolleeSecurity::provisionSecurityForCloudServer(
312             std::string cloudUuid, int credId)
313         {
314             // Need to discover Owned device in a given network, again
315             OC::DeviceList_t pOwnedDevList;
316             std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
317
318             pOwnedDevList.clear();
319
320             OCStackResult result;
321
322             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
323                     pOwnedDevList);
324             if (result != OC_STACK_OK)
325             {
326                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
327                 //Throw exception
328                 throw ESPlatformException(result);
329             }
330             else if (pOwnedDevList.size())
331             {
332                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
333                         pOwnedDevList.size());
334                 ownedDevice = findEnrolleeSecurityResource(pOwnedDevList);
335
336                 if (!ownedDevice)
337                 {
338                     OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found matched owned device.");
339                     throw ESException("Not found matched owned device.");
340                 }
341             }
342             else
343             {
344                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
345                 throw ESException("Not found owned devices.");
346             }
347
348             if(cloudUuid.empty())
349             {
350                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
351                          "ACL provisioning is skipped due to empty UUID of cloud server");
352             }
353             else if(performACLProvisioningForCloudServer(ownedDevice, cloudUuid) != ESResult::ES_OK)
354             {
355                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performACLProvisioningForCloudServer");
356                 throw ESException("error performACLProvisioningForCloudServer");
357             }
358
359             if(credId < 1)
360             {
361                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
362                          "Cert. provisioning is skipped due to wrong cred ID (<1)");
363             }
364             else if(performCertProvisioningForCloudServer(ownedDevice, credId) != ESResult::ES_OK)
365             {
366                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performCertProvisioningForCloudServer");
367                 throw ESException("error performCertProvisioningForCloudServer");
368             }
369         }
370
371         ESResult EnrolleeSecurity::performCertProvisioningForCloudServer(
372             std::shared_ptr< OC::OCSecureResource > ownedDevice, int credId)
373         {
374             ESResult res = ESResult::ES_ERROR;
375
376             if(!ownedDevice)
377             {
378                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
379                 return res;
380             }
381             OC::ResultCallBack CertProvisioningCb = std::bind(
382                             &EnrolleeSecurity::CertProvisioningCb, this, std::placeholders::_1,
383                             std::placeholders::_2);
384             OCStackResult rst = ownedDevice->provisionTrustCertChain(SIGNED_ASYMMETRIC_KEY,
385                                                                     static_cast<uint16_t>(credId),
386                                                                     CertProvisioningCb);
387             if(OC_STACK_OK != rst)
388             {
389                 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "provisionTrustCertChain error: %d", rst);
390                 return res;
391             }
392
393             std::unique_lock<std::mutex> lck(m_mtx);
394             m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
395
396             if(certResult)
397             {
398                 res = ESResult::ES_OK;
399             }
400
401             return res;
402         }
403
404         ESResult EnrolleeSecurity::performACLProvisioningForCloudServer(
405             std::shared_ptr< OC::OCSecureResource > ownedDevice, std::string& cloudUuid)
406         {
407             ESResult res = ESResult::ES_ERROR;
408
409             if(!ownedDevice)
410             {
411                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
412                 return res;
413             }
414             if(cloudUuid.empty())
415             {
416                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
417                 return res;
418             }
419
420             OicUuid_t uuid;
421             ConvertStrToUuid(cloudUuid.c_str(), &uuid);
422
423             // Create Acl for Cloud Server to be provisioned to Enrollee
424             OicSecAcl_t* acl = createAcl(uuid);
425             if(!acl)
426             {
427                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
428                 return res;
429             }
430
431             OC::ResultCallBack aclProvisioningCb = std::bind(
432                             &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
433                             std::placeholders::_2);
434             // ACL provisioning to Enrollee
435             OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
436             if(OC_STACK_OK != rst)
437             {
438                 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
439                 return res;
440             }
441
442             std::unique_lock<std::mutex> lck(m_mtx);
443             m_cond.wait_for(lck, std::chrono::seconds(ES_SEC_DISCOVERY_TIMEOUT));
444
445             if(aclResult)
446             {
447                 res = ESResult::ES_OK;
448             }
449
450             return res;
451         }
452
453         OicSecAcl_t* EnrolleeSecurity::createAcl(const OicUuid_t cloudUuid)
454         {
455             // allocate memory for |acl| struct
456             OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
457             if(!acl)
458             {
459                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
460                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
461             }
462             OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
463             if(!ace)
464             {
465                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
466                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
467             }
468             LL_APPEND(acl->aces, ace);
469
470             memcpy(&ace->subjectuuid, &cloudUuid, UUID_LENGTH);
471
472             OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
473             if(!rsrc)
474             {
475                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
476                 OCDeleteACLList(acl);
477                 return NULL;
478             }
479
480             char href[] = "*";
481             size_t len = strlen(href)+1;  // '1' for null termination
482             rsrc->href = (char*) OICCalloc(len, sizeof(char));
483             if(!rsrc->href)
484             {
485                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
486                 OCDeleteACLList(acl);
487                 return NULL;
488             }
489             OICStrcpy(rsrc->href, len, href);
490
491             size_t arrLen = 1;
492             rsrc->typeLen = arrLen;
493             rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
494             rsrc->interfaceLen = 1;
495             rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
496             rsrc->types[0] = OICStrdup("rt");   // ignore
497             rsrc->interfaces[0] = OICStrdup("if");  // ignore
498
499             LL_APPEND(ace->resources, rsrc);
500
501             ace->permission = 31;   // R/W/U/D
502
503             return acl;
504         }
505
506         void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
507         {
508             if (hasError)
509             {
510                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in ACL provisioning operation!");
511                aclResult = false;
512             }
513             else
514             {
515                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received ACL provisioning results: ");
516
517                std::string devUuid;
518                for (unsigned int i = 0; i < result->size(); i++)
519                {
520                    convertUUIDToString(result->at(i).deviceId.id, devUuid);
521                    OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d  for device %s",
522                                                            result->at(i).res, devUuid.c_str());
523                }
524                delete result;
525                aclResult = true;
526             }
527             m_cond.notify_all();
528         }
529
530         void EnrolleeSecurity::CertProvisioningCb(PMResultList_t *result, int hasError)
531         {
532             if (hasError)
533             {
534                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in Cert. provisioning operation!");
535                certResult = false;
536             }
537             else
538             {
539                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received Cert. provisioning results: ");
540
541                std::string devUuid;
542                for (unsigned int i = 0; i < result->size(); i++)
543                {
544                    convertUUIDToString(result->at(i).deviceId.id, devUuid);
545                    OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d  for device %s",
546                                                            result->at(i).res, devUuid.c_str());
547                }
548                delete result;
549                certResult= true;
550             }
551             m_cond.notify_all();
552         }
553 #endif //defined(__WITH_DTLS__) && defined(__WITH_TLS__)
554     }
555 }