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