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