e3d9b9d747343d1dea1362056cb21011c155bf53
[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                 OTMResult = false;
115             }
116             else
117             {
118                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "ownershipTransferCb : Received provisioning results: ");
119                 for (unsigned int i = 0; i < result->size(); i++)
120                 {
121                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res);
122                 }
123                 delete result;
124                 OTMResult = true;
125             }
126             m_cond.notify_all();
127         }
128
129         ESResult EnrolleeSecurity::provisionOwnership()
130         {
131             ESResult res = ESResult::ES_ERROR;
132
133             OC::DeviceList_t pUnownedDevList, pOwnedDevList;
134
135             pOwnedDevList.clear();
136             pUnownedDevList.clear();
137
138             OCStackResult result = OC_STACK_ERROR;
139
140             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
141                     pOwnedDevList);
142             if (result != OC_STACK_OK)
143             {
144                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
145                 res = ESResult:: ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
146                 return res;
147             }
148             else if (pOwnedDevList.size())
149             {
150                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
151                         pOwnedDevList.size());
152                 std::shared_ptr< OC::OCSecureResource > ownedDevice =
153                     findEnrolleeSecurityResource(pOwnedDevList);
154
155                 if (ownedDevice)
156                 {
157                     if (isOwnedDeviceRegisteredInSVRDB())
158                     {
159                         res = ESResult::ES_OK;
160                     }
161                     else
162                     {
163                         OIC_LOG(ERROR, ENROLEE_SECURITY_TAG,
164                                 "The found owned device is not in Mediator's PDM.");
165                         res = ESResult::ES_ERROR;
166                     }
167                     return res;
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                 res = ESResult:: ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
176                 return res;
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 = findEnrolleeSecurityResource(pUnownedDevList);
184                 if (m_unownedDevice)
185                 {
186                     if(isOwnedDeviceRegisteredInSVRDB())
187                     {
188                         OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
189                             "Found Unowned device's DevID at DB of ownedDevices list");
190
191                         OC::ResultCallBack removeDeviceWithUuidCB = std::bind(
192                                 &EnrolleeSecurity::removeDeviceWithUuidCB,
193                                 this, std::placeholders::_1, std::placeholders::_2);
194
195                         result = OCSecure::removeDeviceWithUuid(DISCOVERY_TIMEOUT,
196                                                                 m_ocResource->sid(),
197                                                                 removeDeviceWithUuidCB);
198                         if(result != OC_STACK_OK)
199                         {
200                             OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "removeDeviceWithUuid failed.");
201                             res = ESResult:: ES_OWNERSHIP_TRANSFER_FAILURE;
202                             return res;
203                         }
204
205                         std::unique_lock<std::mutex> lck(m_mtx);
206                         m_cond.wait(lck);
207
208                         if(!removeDeviceResult)
209                         {
210                             res = ESResult:: ES_OWNERSHIP_TRANSFER_FAILURE;
211                             return res;
212                         }
213                     }
214
215                     res = performOwnershipTransfer();
216
217                     if(res != ESResult::ES_OK)
218                     {
219                         OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Ownership-Transfer failed.");
220                         res = ESResult:: ES_OWNERSHIP_TRANSFER_FAILURE;
221                         return res;
222                     }
223
224                     std::unique_lock<std::mutex> lck(m_mtx);
225                     m_cond.wait(lck);
226
227                     if(!OTMResult)
228                     {
229                         res = ESResult::ES_OWNERSHIP_TRANSFER_FAILURE;
230                     }
231                 }
232                 else
233                 {
234                     OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No matched unowned devices found.");
235                     res = ESResult:: ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
236                 }
237             }
238             else
239             {
240                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No unowned devices found.");
241                 res = ESResult:: ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
242             }
243             return res;
244         }
245
246         ESResult EnrolleeSecurity::performOwnershipTransfer()
247         {
248             OCStackResult result = OC_STACK_ERROR;
249
250             OTMCallbackData_t justWorksCBData;
251             justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
252             justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
253             justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
254             justWorksCBData.createOwnerTransferPayloadCB =
255                     CreateJustWorksOwnerTransferPayload;
256             OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
257
258             OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
259                     m_unownedDevice->getDeviceID().c_str());
260
261             OC::ResultCallBack ownershipTransferCb = std::bind(
262                     &EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
263                     std::placeholders::_2);
264
265             result = m_unownedDevice->doOwnershipTransfer(ownershipTransferCb);
266             if (result != OC_STACK_OK)
267             {
268                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "doOwnershipTransfer is failed");
269                 return ESResult::ES_ERROR;
270             }
271             return ESResult::ES_OK;
272         }
273
274         void EnrolleeSecurity::removeDeviceWithUuidCB(OC::PMResultList_t *result, int hasError)
275         {
276             if (hasError)
277             {
278                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in removeDeviceWithUuid operation!");
279                removeDeviceResult = false;
280             }
281
282             else
283             {
284                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
285
286                for (unsigned int i = 0; i < result->size(); i++)
287                {
288                     std::string uuid;
289                     convertUUIDToString(result->at(i).deviceId.id, uuid);
290
291                     OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
292                         "Result is = %d for device %s",  result->at(i).res, uuid.c_str());
293                }
294                removeDeviceResult = true;
295             }
296             m_cond.notify_all();
297         }
298
299         bool EnrolleeSecurity::isOwnedDeviceRegisteredInSVRDB()
300         {
301             OCStackResult res = OC_STACK_ERROR;
302
303             OCUuidList_t *uuidList = NULL;
304             size_t numOfDevices = 0;
305
306             res = PDMGetOwnedDevices(&uuidList, &numOfDevices);
307             if (OC_STACK_OK != res)
308             {
309                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error while getting info from DB");
310                 return false;
311             }
312
313             OCUuidList_t *pUuidList = uuidList;
314
315             while (pUuidList)
316             {
317                 std::string uuid;
318                 convertUUIDToString(pUuidList->dev.id, uuid);
319                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG,
320                     "m_ocResource->sid(): %s, cur DB UUID %s",
321                     m_ocResource->sid().c_str(), uuid.c_str());
322                 if(m_ocResource->sid() == uuid.c_str())
323                 {
324                     return true;
325                 }
326                 pUuidList = pUuidList->next;
327             }
328             return false;
329         }
330
331
332         std::string EnrolleeSecurity::getUUID() const
333         {
334             return m_ocResource->sid();
335         };
336
337 #if defined(__WITH_DTLS__) && defined(__WITH_TLS__)
338         ESResult EnrolleeSecurity::provisionSecurityForCloudServer(
339             std::string cloudUuid, int credId)
340         {
341             ESResult res = ESResult::ES_ERROR;
342
343             // Need to discover Owned device in a given network, again
344             OC::DeviceList_t pOwnedDevList;
345             std::shared_ptr< OC::OCSecureResource > ownedDevice = NULL;
346
347             pOwnedDevList.clear();
348
349             OCStackResult result;
350
351             result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
352                     pOwnedDevList);
353             if (result != OC_STACK_OK)
354             {
355                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
356                 res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
357                 return res;
358             }
359             else if (pOwnedDevList.size())
360             {
361                 OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
362                         pOwnedDevList.size());
363                 ownedDevice = findEnrolleeSecurityResource(pOwnedDevList);
364
365                 if (!ownedDevice)
366                 {
367                     OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found matched owned device.");
368                     res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
369                     return res;
370                 }
371             }
372             else
373             {
374                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Not found owned devices.");
375                 res = ESResult::ES_SECURE_RESOURCE_DISCOVERY_FAILURE;
376                 return res;
377             }
378
379             if(cloudUuid.empty())
380             {
381                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
382                          "ACL provisioning is skipped due to empty UUID of cloud server");
383             }
384             else
385             {
386                 res = performACLProvisioningForCloudServer(ownedDevice, cloudUuid);
387                 if(res != ESResult::ES_OK)
388                 {
389                     OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performACLProvisioningForCloudServer");
390                     return res;
391                 }
392             }
393
394             if(credId < 1)
395             {
396                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
397                          "Cert. provisioning is skipped due to wrong cred ID (<1)");
398             }
399             else
400             {
401                 res = performCertProvisioningForCloudServer(ownedDevice, credId);
402                 if(res != ESResult::ES_OK)
403                 {
404                     OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "error performCertProvisioningForCloudServer");
405                     return res;
406                 }
407             }
408
409             return res;
410         }
411
412         ESResult EnrolleeSecurity::performCertProvisioningForCloudServer(
413             std::shared_ptr< OC::OCSecureResource > ownedDevice, int credId)
414         {
415             ESResult res = ESResult::ES_CERT_PROVISIONING_FAILURE;
416
417             if(!ownedDevice)
418             {
419                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
420                 return res;
421             }
422             OC::ResultCallBack CertProvisioningCb = std::bind(
423                             &EnrolleeSecurity::CertProvisioningCb, this, std::placeholders::_1,
424                             std::placeholders::_2);
425             OCStackResult rst = ownedDevice->provisionTrustCertChain(SIGNED_ASYMMETRIC_KEY,
426                                                                     static_cast<uint16_t>(credId),
427                                                                     CertProvisioningCb);
428             if(OC_STACK_OK != rst)
429             {
430                 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "provisionTrustCertChain error: %d", rst);
431                 return res;
432             }
433
434             std::unique_lock<std::mutex> lck(m_mtx);
435             m_cond.wait(lck);
436
437             if(certResult)
438             {
439                 res = ESResult::ES_OK;
440             }
441
442             return res;
443         }
444
445         ESResult EnrolleeSecurity::performACLProvisioningForCloudServer(
446             std::shared_ptr< OC::OCSecureResource > ownedDevice, std::string& cloudUuid)
447         {
448             ESResult res = ESResult::ES_ACL_PROVISIONING_FAILURE;
449
450             if(!ownedDevice)
451             {
452                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Invalid param");
453                 return res;
454             }
455
456             OicUuid_t uuid;
457             ConvertStrToUuid(cloudUuid.c_str(), &uuid);
458
459             // Create Acl for Cloud Server to be provisioned to Enrollee
460             OicSecAcl_t* acl = createAcl(uuid);
461             if(!acl)
462             {
463                 OIC_LOG(ERROR, ENROLEE_SECURITY_TAG, "createAcl error return");
464                 return res;
465             }
466
467             OC::ResultCallBack aclProvisioningCb = std::bind(
468                             &EnrolleeSecurity::ACLProvisioningCb, this, std::placeholders::_1,
469                             std::placeholders::_2);
470             // ACL provisioning to Enrollee
471             OCStackResult rst = ownedDevice->provisionACL(acl, aclProvisioningCb);
472             if(OC_STACK_OK != rst)
473             {
474                 OIC_LOG_V(ERROR, ENROLEE_SECURITY_TAG, "OCProvisionACL API error: %d", rst);
475                 return res;
476             }
477
478             std::unique_lock<std::mutex> lck(m_mtx);
479             m_cond.wait(lck);
480
481             if(aclResult)
482             {
483                 res = ESResult::ES_OK;
484             }
485
486             return res;
487         }
488
489         OicSecAcl_t* EnrolleeSecurity::createAcl(const OicUuid_t cloudUuid)
490         {
491             // allocate memory for |acl| struct
492             OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
493             if(!acl)
494             {
495                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
496                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
497             }
498             OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
499             if(!ace)
500             {
501                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
502                 return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
503             }
504             LL_APPEND(acl->aces, ace);
505
506             memcpy(&ace->subjectuuid, &cloudUuid, UUID_LENGTH);
507
508             OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
509             if(!rsrc)
510             {
511                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "createAcl: OICCalloc error return");
512                 OCDeleteACLList(acl);
513                 return NULL;
514             }
515
516             char href[] = "*";
517             size_t len = strlen(href)+1;  // '1' for null termination
518             rsrc->href = (char*) OICCalloc(len, sizeof(char));
519             if(!rsrc->href)
520             {
521                 OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG,  "createAcl: OICCalloc error return");
522                 OCDeleteACLList(acl);
523                 return NULL;
524             }
525             OICStrcpy(rsrc->href, len, href);
526
527             size_t arrLen = 1;
528             rsrc->typeLen = arrLen;
529             rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
530             rsrc->interfaceLen = 1;
531             rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
532             rsrc->types[0] = OICStrdup("rt");   // ignore
533             rsrc->interfaces[0] = OICStrdup("if");  // ignore
534
535             LL_APPEND(ace->resources, rsrc);
536
537             ace->permission = 31;   // R/W/U/D
538
539             return acl;
540         }
541
542         void EnrolleeSecurity::ACLProvisioningCb(PMResultList_t *result, int hasError)
543         {
544             if (hasError)
545             {
546                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in ACL provisioning operation!");
547                aclResult = false;
548             }
549             else
550             {
551                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received ACL provisioning results: ");
552
553                std::string devUuid;
554                for (unsigned int i = 0; i < result->size(); i++)
555                {
556                    convertUUIDToString(result->at(i).deviceId.id, devUuid);
557                    OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d  for device %s",
558                                                            result->at(i).res, devUuid.c_str());
559                }
560                delete result;
561                aclResult = true;
562             }
563             m_cond.notify_all();
564         }
565
566         void EnrolleeSecurity::CertProvisioningCb(PMResultList_t *result, int hasError)
567         {
568             if (hasError)
569             {
570                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Error in Cert. provisioning operation!");
571                aclResult = false;
572             }
573             else
574             {
575                OIC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received Cert. provisioning results: ");
576
577                std::string devUuid;
578                for (unsigned int i = 0; i < result->size(); i++)
579                {
580                    convertUUIDToString(result->at(i).deviceId.id, devUuid);
581                    OIC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d  for device %s",
582                                                            result->at(i).res, devUuid.c_str());
583                }
584                delete result;
585                certResult= true;
586             }
587             m_cond.notify_all();
588         }
589 #endif //defined(__WITH_DTLS__) && defined(__WITH_TLS__)
590     }
591 }