1 /* *****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * *****************************************************************/
29 #include <condition_variable>
32 #include "oic_malloc.h"
33 #include "oic_string.h"
34 #include "OCPlatform.h"
36 #include "OCProvisioningManager.h"
37 #include "oxmjustworks.h"
38 #include "oxmrandompin.h"
40 #define MAX_URI_LENGTH (64)
41 #define MAX_PERMISSION_LENGTH (5)
48 #define PREDEFINED_TIMEOUT (10)
49 #define MAX_OWNED_DEVICE (10)
50 #define TAG "provisioningclient"
52 #define JSON_DB_PATH "./oic_svr_db_client.json"
53 #define DEV_STATUS_ON "DEV_STATUS_ON"
54 #define DEV_STATUS_OFF "DEV_STATUS_OFF"
56 #define DISCOVERY_TIMEOUT 5
60 DeviceList_t pUnownedDevList, pOwnedDevList;
61 static int transferDevIdx, ask = 1;
63 static FILE* client_open(const char *UNUSED_PARAM, const char *mode)
66 return fopen(JSON_DB_PATH, mode);
71 std::cout << "\nChoose an option:"<<std::endl;
72 std::cout << " 1. UnOwned Device discovery"<<std::endl;
73 std::cout << " 2. Owned Device discovery"<<std::endl;
74 std::cout << " 3. Ownership transfer"<<std::endl;
75 std::cout << " 4. Provision ACL"<<std::endl;
76 std::cout << " 5. Provision Credentials"<<std::endl;
77 std::cout << " 6. Credential & ACL provisioning b/w two devices"<<std::endl;
78 std::cout << " 7. Unlink Devices"<<std::endl;
79 std::cout << " 8. Remove Device"<<std::endl;
80 std::cout << " 9. Get Linked Devices"<<std::endl;
81 std::cout << " 10. Get Device Status"<<std::endl;
82 std::cout << " 11. Exit loop"<<std::endl;
85 void moveTransferredDevice()
87 pOwnedDevList.push_back(pUnownedDevList[transferDevIdx]);
88 pUnownedDevList.erase(pUnownedDevList.begin() + transferDevIdx);
91 void InputPinCB(char* pinBuf, size_t bufSize)
95 std::cout <<"INPUT PIN : ";
98 OICStrcpy(pinBuf, bufSize, ptr.c_str());
103 void printUuid(OicUuid_t uuid)
105 for (int i = 0; i < UUID_LENGTH; i++)
107 std::cout <<std::hex << uuid.id[i] << " ";
109 std::cout<<std::endl;
112 void ownershipTransferCB(PMResultList_t *result, int hasError)
116 std::cout << "Error!!! in OwnershipTransfer"<<std::endl;
120 std::cout<< "\nTransferred Ownership successfuly for device : ";
121 printUuid(result->at(0).deviceId);
124 moveTransferredDevice();
129 void printStatus(int status)
131 static std::map<int, std::string> devStatus = {{1<<0, DEV_STATUS_ON}, {1<<1, DEV_STATUS_OFF}};
133 std::cout <<devStatus[status] <<std::endl;
136 void printDevices(DeviceList_t &list)
138 for (unsigned int i = 0; i < list.size(); i++ )
140 std::cout << "Device "<< i+1 <<" ID: ";
141 std::cout << list[i]->getDeviceID() << " From IP: ";
142 std::cout << list[i]->getDevAddr() << std::endl;
147 * Callback function for provisioning ACL, Credentials.
149 * @param[in] result Result list
150 * @param[in] hasError indicates if the result has error
152 void provisionCB(PMResultList_t *result, int hasError)
156 std::cout << "Error in provisioning operation!"<<std::endl;
160 std::cout<< "\nReceived provisioning results: ";
161 for (unsigned int i = 0; i < result->size(); i++)
163 std::cout << "Result is = " << result->at(i).res <<" for device ";
164 printUuid(result->at(i).deviceId);
174 * Ask user with which devices it wants to make further actions.
175 * All possible error checks included.
176 * Default behavior in case if only one options leaves are included too.
177 * Expect that user count devices from 1, f.e. 1st, 2nd, 3rd, etc
178 * Use DeviceList_t instead of devicesCount because of print devices info
180 * @param[in] list owned devices list.
181 * @param[out] out device number array.
182 * @param[in] count how many device numbers need to read.
183 * @return 0 in case of success and other value otherwise.
185 int readDeviceNumber(DeviceList_t &list, int count, int *out)
187 if (out == NULL || count <= 0)
189 std::cout << "Error! Please put valid input parameters" << std::endl;
193 int devicesCount = list.size();
195 //Print current list of owned devices
196 std::cout <<"Owned devices, count = " << devicesCount << std::endl;
199 if (devicesCount < count)
201 std::cout << "You can't proceed with selected action because Owned devices count ( ";
202 std::cout << devicesCount << " ) are less then required devices ( " << count << " ).";
203 std::cout << "You may need to discover devices again" << std::endl;
207 std::cout << "Select " << count << " device(s) for provisioning" << std::endl;
209 for (int curr = 0; curr < count; curr++)
211 //select last device by default if only 1 option exist
212 //from user's point of view device counting starts from 1,
213 //so 1st, 2nd, 3rd, etc devices
214 if ((curr == count - 1) && (devicesCount == count))
217 for (int i = 0; i < curr; i++)
222 out[curr] = (count*(count+1))/2 - sum;
224 std::cout << "Device " << curr + 1 << " : " << out[curr];
225 std::cout << " - selected automatically (because no other options exist)" << std::endl;
230 std::cout << "Device " << curr + 1 << " : ";
233 if (choice < 1 || choice > devicesCount)
235 std::cout << "Error! You should enter valid device number!" << std::endl;
239 //check that user doesn't select the same device twice
240 for (int i = 0; i < curr; i++)
242 if (out[i] == choice)
244 std::cout << "Error! You cannot select the same device twice!" << std::endl;
252 //Users count devices from 1, so 1st, 2nd, 3rd, etc device
253 //But deviceList array start index is 0, so need to decrease all numbers to 1
254 for (int i = 0; i < count; i++) out[i] -= 1;
260 * Perform cleanup for ACL
263 static void deleteACL(OicSecAcl_t *acl)
267 /* Clean Resources */
268 for (unsigned int i = 0; i < (acl)->resourcesLen; i++)
270 OICFree((acl)->resources[i]);
272 OICFree((acl)->resources);
275 OICFree((acl)->owners);
277 /* Clean ACL node itself */
278 /* Required only if acl was created in heap */
284 * Calculate ACL permission from string to bit
286 * @param[in] temp_psm Input data of ACL permission string
287 * @param[in,out] pms The pointer of ACL permission value
288 * @return 0 on success otherwise -1.
290 static int CalculateAclPermission(const char *temp_pms, uint16_t *pms)
294 if (NULL == temp_pms || NULL == pms)
299 while (temp_pms[i] != '\0')
348 * Get the ACL property from user
350 * @param[in] ACL Datastructure to save user inputs
351 * @return 0 on success otherwise -1.
353 static int InputACL(OicSecAcl_t *acl)
356 char *temp_id, *temp_rsc, *temp_pms;
358 printf("******************************************************************************\n");
359 printf("-Set ACL policy for target device\n");
360 printf("******************************************************************************\n");
362 printf("-URN identifying the subject\n");
363 printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n");
364 printf("Subject : ");
365 ret = scanf("%19ms", &temp_id);
369 for (int i = 0, j = 0; temp_id[i] != '\0'; i++)
371 if (DASH != temp_id[i])
372 acl->subject.id[j++] = temp_id[i];
378 printf("Error while input\n");
383 printf("Num. of Resource : ");
384 ret = scanf("%zu", &acl->resourcesLen);
385 if ((1 != ret) || (acl->resourcesLen <= 0 || acl->resourcesLen > 50))
387 printf("Error while input\n");
390 printf("-URI of resource\n");
391 printf("ex)/oic/sh/temp/0 (Max_URI_Length: 64 Byte )\n");
392 acl->resources = (char **)OICCalloc(acl->resourcesLen, sizeof(char *));
393 if (NULL == acl->resources)
395 OIC_LOG(ERROR, TAG, "Error while memory allocation");
398 for (size_t i = 0; i < acl->resourcesLen; i++)
400 printf("[%zu]Resource : ", i + 1);
401 ret = scanf("%64ms", &temp_rsc);
404 printf("Error while input\n");
408 acl->resources[i] = OICStrdup(temp_rsc);
410 if (NULL == acl->resources[i])
412 OIC_LOG(ERROR, TAG, "Error while memory allocation");
419 printf("-Set the permission(C,R,U,D,N)\n");
420 printf("ex) CRUDN, CRU_N,..(5 Charaters)\n");
421 printf("Permission : ");
422 ret = scanf("%5ms", &temp_pms);
425 printf("Error while input\n");
428 ret = CalculateAclPermission(temp_pms, &(acl->permission));
433 printf("Num. of Rowner : ");
434 ret = scanf("%zu", &acl->ownersLen);
435 if ((1 != ret) || (acl->ownersLen <= 0 || acl->ownersLen > 20))
437 printf("Error while input\n");
440 printf("-URN identifying the rowner\n");
441 printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n");
442 acl->owners = (OicUuid_t *)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
443 if (NULL == acl->owners)
445 OIC_LOG(ERROR, TAG, "Error while memory allocation");
448 for (size_t i = 0; i < acl->ownersLen; i++)
450 printf("[%zu]Rowner : ", i + 1);
451 ret = scanf("%19ms", &temp_id);
454 printf("Error while input\n");
458 for (int k = 0, j = 0; temp_id[k] != '\0'; k++)
460 if (DASH != temp_id[k])
462 acl->owners[i].id[j++] = temp_id[k];
470 static int InputCredentials(Credential &cred)
476 std::cout << "Select credential type from following values:" << std::endl;
477 std::cout << "1: symmetric pair-wise key" << std::endl;
478 std::cout << "2: symmetric group key" << std::endl;
479 std::cout << "4: asymmetric key" << std::endl;
480 std::cout << "8: signed asymmetric key (aka certificate)" << std::endl;
481 std::cout << "16: PIN /password" << std::endl;
482 std::cout << "Your choice: ";
488 cred.setCredentialType(static_cast<OicSecCredType_t>(choice));
489 choice = 0; //validation of the accepted choice.
495 std::cout << "selected type is not supported yet" << std::endl;
498 std::cout << "Error! Please select valid credential type" << std::endl;
501 } while(0 != choice);
503 std::cout << "Please enter key size (valid size is 128 or 256) :";
508 cred.setCredentialKeySize(OWNER_PSK_LENGTH_128);
510 else if(256 == choice)
512 cred.setCredentialKeySize(OWNER_PSK_LENGTH_256);
516 std::cout << "Error! Please enter valid key size!" << std::endl;
525 OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
527 // Create PlatformConfig object
529 OC::ServiceType::InProc,
533 OC::QualityOfService::LowQos,
537 OCPlatform::Configure(cfg);
542 OicSecAcl_t *acl1 = nullptr, *acl2 = nullptr;
543 if (OCSecure::provisionInit("") != OC_STACK_OK)
545 std::cout <<"PM Init failed"<< std::endl;
549 for (int out = 0; !out;)
573 //Secure resource discovery.
575 pUnownedDevList.clear();
576 std::cout << "Started discovery..." <<std::endl;
577 OCStackResult result = OCSecure::discoverUnownedDevices(DISCOVERY_TIMEOUT,
579 if (result != OC_STACK_OK)
581 std::cout<< "!!Error - UnOwned Discovery failed."<<std::endl;
583 else if (pUnownedDevList.size())
585 std::cout <<"Found secure devices, count = " <<
586 pUnownedDevList.size() << std::endl;
587 printDevices(pUnownedDevList);
591 std::cout <<"No Secure devices found"<<std::endl;
597 pOwnedDevList.clear();
598 std::cout << "Started discovery..." <<std::endl;
599 OCStackResult result = OCSecure::discoverOwnedDevices(DISCOVERY_TIMEOUT,
601 if (result != OC_STACK_OK)
603 std::cout<< "!!Error - Owned Discovery failed."<<std::endl;
605 else if (pOwnedDevList.size())
607 std::cout <<"Found owned devices, count = " <<
608 pOwnedDevList.size() << std::endl;
609 printDevices(pOwnedDevList);
613 std::cout <<"No Secure devices found"<<std::endl;
621 if (!pUnownedDevList.size())
623 std::cout <<"There are no more Unowned devices"<<std::endl;
627 for (unsigned int i = 0; i < pUnownedDevList.size(); i++ )
629 std::cout << i+1 << ": "<< pUnownedDevList[i]->getDeviceID();
630 std::cout << " From IP:" << pUnownedDevList[i]->getDevAddr() <<std::endl;
633 std::cout <<"Select device number: "<<std::endl;
635 if (devNum > pUnownedDevList.size())
637 std::cout <<"Invalid device number"<<std::endl;
640 transferDevIdx = devNum - 1;
642 //register callbacks for JUST WORKS and PIN methods
643 std::cout <<"Registering OTM Methods: 1. JUST WORKS and 2. PIN"<<std::endl;
646 OTMCallbackData_t justWorksCBData;
647 justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
648 justWorksCBData.createSecureSessionCB =
649 CreateSecureSessionJustWorksCallback;
650 justWorksCBData.createSelectOxmPayloadCB =
651 CreateJustWorksSelectOxmPayload;
652 justWorksCBData.createOwnerTransferPayloadCB =
653 CreateJustWorksOwnerTransferPayload;
654 OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS,
655 &justWorksCBData, NULL);
659 OTMCallbackData_t pinBasedCBData;
660 pinBasedCBData.loadSecretCB = InputPinCodeCallback;
661 pinBasedCBData.createSecureSessionCB =
662 CreateSecureSessionRandomPinCallbak;
663 pinBasedCBData.createSelectOxmPayloadCB =
664 CreatePinBasedSelectOxmPayload;
665 pinBasedCBData.createOwnerTransferPayloadCB =
666 CreatePinBasedOwnerTransferPayload;
667 OCSecure::setOwnerTransferCallbackData(OIC_RANDOM_DEVICE_PIN,
668 &pinBasedCBData, InputPinCB);
672 std::cout << "Transfering ownership for : "<<
673 pUnownedDevList[devNum-1]->getDeviceID()<<std::endl;
674 if (pUnownedDevList[devNum-1]->doOwnershipTransfer(ownershipTransferCB)
677 std::cout<<"OwnershipTransferCallback is failed"<<std::endl;
682 case 4: //Provision ACL
686 if (0 != readDeviceNumber(pOwnedDevList, 1, &index)) break;
688 std::cout << "Provision ACL for : "<<
689 pOwnedDevList[index]->getDeviceID()<< std::endl;
691 acl1 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t));
694 OIC_LOG(ERROR, TAG, "Error while memory allocation");
698 std::cout << "Please input ACL for selected device: " << std::endl;
699 if (0 != InputACL(acl1))
706 if (pOwnedDevList[index]->provisionACL(acl1, provisionCB) != OC_STACK_OK)
709 std::cout <<"provisionACL is failed"<< std::endl;
713 case 5: //Provision Credentials
717 if (0 != readDeviceNumber(pOwnedDevList, 2, devices)) break;
719 int first = devices[0];
720 int second = devices[1];
722 std::cout << "Provision Credentials to devices: "<<
723 pOwnedDevList[first]->getDeviceID();
724 std::cout << " and "<< pOwnedDevList[second]->getDeviceID() << std::endl;
726 Credential cred( NO_SECURITY_MODE ,0);
727 std::cout << "Please input credentials for selected devices: " << std::endl;
728 if (0 != InputCredentials(cred))
733 if (pOwnedDevList[first]->provisionCredentials(cred,
734 *pOwnedDevList[second].get(), provisionCB) != OC_STACK_OK)
737 std::cout <<"provisionCredentials is failed"<< std::endl;
741 case 6: //Provision ACL & Creds b/w two devices.
745 if (0 != readDeviceNumber(pOwnedDevList, 2, devices)) break;
747 int first = devices[0];
748 int second = devices[1];
750 std::cout << "Provision pairwise devices: "<<
751 pOwnedDevList[first]->getDeviceID();
752 std::cout << " and "<< pOwnedDevList[second]->getDeviceID() << std::endl;
754 Credential cred( NO_SECURITY_MODE, 0);
755 std::cout << "Please input credentials for selected devices: " << std::endl;
756 if (0 != InputCredentials(cred))
759 acl1 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t));
762 OIC_LOG(ERROR, TAG, "Error while memory allocation");
766 std::cout << "Please input ACL for selected device: " << std::endl;
767 if (0 != InputACL(acl1))
772 acl2 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t));
775 OIC_LOG(ERROR, TAG, "Error while memory allocation");
779 std::cout << "Please input ACL for selected device: " << std::endl;
780 if (0 != InputACL(acl2))
787 if (pOwnedDevList[first]->provisionPairwiseDevices(cred, acl1,
788 *pOwnedDevList[second].get(), acl2, provisionCB) != OC_STACK_OK)
791 std::cout <<"provisionPairwiseDevices is failed"<< std::endl;
795 case 7: //Unlink Devices
799 if (0 != readDeviceNumber(pOwnedDevList, 2, devices)) break;
801 int first = devices[0];
802 int second = devices[1];
804 std::cout << "Unlink devices: "<< pOwnedDevList[first]->getDeviceID();
805 std::cout << " and "<< pOwnedDevList[second]->getDeviceID() << std::endl;
809 if (pOwnedDevList[first]->unlinkDevices(*pOwnedDevList[second].get(),
810 provisionCB) != OC_STACK_OK)
813 std::cout <<"unlinkDevice is failed"<< std::endl;
817 case 8: //Remove Device
821 if (0 != readDeviceNumber(pOwnedDevList, 1, &index)) break;
823 std::cout << "Remove Device: "<< pOwnedDevList[index]->getDeviceID()<< std::endl;
827 if (pOwnedDevList[index]->removeDevice(DISCOVERY_TIMEOUT, provisionCB)
831 std::cout <<"removeDevice is failed"<< std::endl;
835 case 9: //Get Linked devices
837 UuidList_t linkedUuid;
840 if (!pOwnedDevList.size())
842 std::cout <<"There are no Owned devices yet,"
843 " may need to discover"<<std::endl;
847 for (unsigned int i = 0; i < pOwnedDevList.size(); i++ )
849 std::cout << i+1 << ": "<< pOwnedDevList[i]->getDeviceID() <<" From IP:";
850 std::cout << pOwnedDevList[i]->getDevAddr() <<std::endl;
853 std::cout <<"Select device number: "<<std::endl;
855 if (devNum > pOwnedDevList.size())
857 std::cout <<"Invalid device number"<<std::endl;
861 if(pOwnedDevList[devNum -1]->getLinkedDevices(linkedUuid) == OC_STACK_OK)
863 if (!linkedUuid.size())
865 std::cout <<"No devices are linked to "<<
866 pOwnedDevList[devNum -1]->getDeviceID() << std::endl;
868 //display the Linked devices (UUIDs)
869 for(unsigned int i = 0; i < linkedUuid.size(); i++)
871 printUuid(linkedUuid[i]);
876 std::cout <<"Error! in getLinkedDevices"<<std::endl;
880 case 10: //Get device' status
882 DeviceList_t unownedList, ownedList;
884 if (OCSecure::getDevInfoFromNetwork(DISCOVERY_TIMEOUT, ownedList,
885 unownedList) == OC_STACK_OK)
887 std::cout <<"Owned Device' status for" <<std::endl;
888 for (unsigned int i = 0; i < ownedList.size(); i++ )
890 std::cout << "Device "<<i+1 <<" ID: '";
891 std::cout << ownedList[i]->getDeviceID() << "' From IP: ";
892 std::cout << ownedList[i]->getDevAddr() << " Status: ";
893 printStatus(ownedList[i]->getDeviceStatus());
895 std::cout <<"\nUnOwned Device' status for" <<std::endl;
896 for (unsigned int i = 0; i < unownedList.size(); i++ )
898 std::cout << "Device "<<i+1 <<" ID: '";
899 std::cout << unownedList[i]->getDeviceID() << "' From IP: ";
900 std::cout << unownedList[i]->getDevAddr() << " Status: ";
901 printStatus(unownedList[i]->getDeviceStatus());
915 catch(OCException& e)
917 oclog() << "Exception in main: "<<e.what();