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