Merge tizen_5.0 codes into tizen_4.0
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / sample / provisioningclient.c
index 85555ed..301a625 100644 (file)
  *
  *****************************************************************/
 
+#include "iotivity_config.h"
+
 #include <stdio.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
+#include "utlist.h"
 #include "logger.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
 #include "securevirtualresourcetypes.h"
 #include "srmutility.h"
 #include "pmtypes.h"
+#include "oxmverifycommon.h"
+#include "oxmrawpublickey.h"
+#include "pkix_interface.h"
+#include "hw_emul/hw_interface.h"
+#include "mbedtls/x509_crt.h"
+#include "secureresourceprovider.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -39,20 +50,40 @@ extern "C"
 
 // declaration(s) for provisioning client using C-level provisioning API
 // user input definition for main loop on provisioning client
-#define _10_DISCOV_ALL_DEVS_    10
-#define _11_DISCOV_UNOWN_DEVS_  11
-#define _12_DISCOV_OWN_DEVS_    12
-#define _20_REGIST_DEVS_        20
-#define _30_PROVIS_PAIR_DEVS_   30
-#define _31_PROVIS_CRED_        31
-#define _32_PROVIS_ACL_         32
-#define _33_PROVIS_DP_           33
-#define _34_CHECK_LINK_STATUS_  34
-#define _40_UNLINK_PAIR_DEVS_   40
-#define _50_REMOVE_SELEC_DEV_   50
-#define _99_EXIT_PRVN_CLT_      99
+#define _10_DISCOV_ALL_DEVS_            10
+#define _11_DISCOV_UNOWN_DEVS_          11
+#define _12_DISCOV_OWN_DEVS_            12
+#ifdef MULTIPLE_OWNER
+#define _13_MOT_DISCOV_DEV_             13
+#endif //MULTIPLE_OWNER
+#define _20_REGIST_DEVS_                20
+#define _30_PROVIS_PAIR_DEVS_           30
+#define _31_PROVIS_CRED_                31
+#define _32_PROVIS_ACL_                 32
+#define _33_PROVIS_DP_                  33
+#define _34_CHECK_LINK_STATUS_          34
+#define _35_SAVE_ACL_                   35
+#define _40_UNLINK_PAIR_DEVS_           40
+#define _50_REMOVE_SELEC_DEV_           50
+#define _51_REMOVE_DEV_WITH_UUID_       51
+#define _52_RESET_SELEC_DEV_            52
+#define _53_RESET_SVR_DB_               53
+#define _60_GET_CRED_                   60
+#define _61_GET_ACL_                    61
+#ifdef MULTIPLE_OWNER
+#define _70_MOT_CHANGE_MOM_             70
+#define _71_MOT_PROV_PRECONF_PIN_       71
+#define _72_MOT_OXM_SEL_                72
+#define _73_MOT_REMOVE_SUBOWNER_        73
+#define _74_MOT_REMOVE_ALL_SUBOWNER_        74
+#endif //MULTIPLE_OWNER
+#define _80_SELECT_PROTOCOL_            80
+#define _81_SELECT_VERIF_METHOD_        81
+#define _82_SECURE_STORAGE_HW_EMULATION_    82
+#define _99_EXIT_PRVN_CLT_              99
 
 #define ACL_RESRC_MAX_NUM   16
+#define ACL_RESRC_ARRAY_SIZE   3 //This value is used only for sample (not OCF spec)
 #define ACL_RESRC_MAX_LEN   128
 #define ACL_PEMISN_CNT      5
 #define DISCOVERY_TIMEOUT   10  // 10 sec
@@ -78,10 +109,19 @@ static OCProvisionDev_t* g_own_list;
 static OCProvisionDev_t* g_unown_list;
 static int g_own_cnt;
 static int g_unown_cnt;
-static bool g_doneCB;
+#ifdef MULTIPLE_OWNER
+static OCProvisionDev_t* g_mot_enable_list;
+static int g_mot_enable_cnt;
+#endif //MULTIPLE_OWNER
 
+static bool g_doneCB;
+#ifdef __WITH_TLS__
+static int secure_protocol = 1;
+static void setDevProtocol(OCProvisionDev_t* dev_lst);
+#endif
 // function declaration(s) for calling them before implementing
 static OicSecAcl_t* createAcl(const int);
+static OicSecAcl_t* createSimpleAcl(const OicUuid_t uuid);
 static OicSecPdAcl_t* createPdAcl(const int);
 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
 static int printDevList(const OCProvisionDev_t*);
@@ -149,6 +189,34 @@ static void provisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool
     g_doneCB = true;
 }
 
+static void getCredCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "getCredCB SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "getCredCB FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+static void getAclCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "getAclCB SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "getAclCB FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
 static void provisionDPCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
 {
     if(!hasError)
@@ -191,9 +259,47 @@ static void removeDeviceCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool
     g_doneCB = true;
 }
 
+static void resetDeviceCB(void* ctx)
+{
+    OC_UNUSED(ctx);
+    OIC_LOG_V(INFO, TAG, "Reset Device SUCCEEDED");
+    g_doneCB = true;
+}
+
+#ifdef MULTIPLE_OWNER
+static void updateDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "POST 'doxm' SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "POST 'doxm'  FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+static void deleteDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "DELETE 'doxm' SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "DELETE 'doxm'  FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+#endif //MULTIPLE_OWNER
+
 static void inputPinCB(char* pin, size_t len)
 {
-    if(!pin || OXM_RANDOM_PIN_SIZE>=len)
+    if(!pin || OXM_RANDOM_PIN_MIN_SIZE > len)
     {
         OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
         return;
@@ -202,12 +308,31 @@ static void inputPinCB(char* pin, size_t len)
     printf("   > INPUT PIN: ");
     for(int ret=0; 1!=ret; )
     {
-        ret = scanf("%8s", pin);
+        ret = scanf("%32s", pin);
         for( ; 0x20<=getchar(); );  // for removing overflow garbages
                                     // '0x20<=code' is character region
     }
 }
 
+static char rpk[32] = {
+    0xB2, 0xA2, 0x0D, 0xC0, 0xCB, 0x3C, 0xA0, 0x27,
+    0x45, 0x00, 0x73, 0xBD, 0x02, 0xF5, 0x84, 0x4B,
+    0x0C, 0x1C, 0xD6, 0x6A, 0xD3, 0x9E, 0x3F, 0x64,
+    0x95, 0x6B, 0xB8, 0xCA, 0x58, 0xBC, 0xBE, 0xBE
+};
+
+static void InputRPKMasterKeyCB(char **rpkMasterKey, size_t *rpkMasterKeyLen)
+{
+    if(!rpkMasterKey || !rpkMasterKeyLen)
+    {
+        OIC_LOG(ERROR, TAG, "InputRPKMasterKeyCB invalid parameters");
+        return;
+    }
+
+    *rpkMasterKey = rpk;
+    *rpkMasterKeyLen = 32;
+}
+
 // function(s) for provisioning client using C-level provisioning API
 static int initProvisionClient(void)
 {
@@ -252,29 +377,8 @@ static int initProvisionClient(void)
         return -1;
     }
 
-    // register callback function(s) to each OxM
-    OTMCallbackData_t otmcb =
-    {
-        .loadSecretCB = LoadSecretJustWorksCallback,
-        .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
-        .createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload,
-        .createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload
-    };
-    if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_JUST_WORKS, &otmcb))
-    {
-        OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_JUST_WORKS");
-        return -1;
-    }
-    otmcb.loadSecretCB = InputPinCodeCallback;
-    otmcb.createSecureSessionCB = CreateSecureSessionRandomPinCallback;
-    otmcb.createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload;
-    otmcb.createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload;
-    if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_RANDOM_DEVICE_PIN, &otmcb))
-    {
-        OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_RANDOM_DEVICE_PIN");
-        return -1;
-    }
     SetInputPinCB(inputPinCB);
+    SetRPKMasterKeyCB(InputRPKMasterKeyCB);
 
     return 0;
 }
@@ -306,7 +410,10 @@ static int discoverAllDevices(void)
     g_own_cnt = printDevList(g_own_list);
     printf("   > Discovered Unowned Devices\n");
     g_unown_cnt = printDevList(g_unown_list);
-
+#ifdef __WITH_TLS__
+    setDevProtocol(g_own_list);
+    setDevProtocol(g_unown_list);
+#endif
     return 0;
 }
 
@@ -331,7 +438,9 @@ static int discoverUnownedDevices(void)
     // display the discovered unowned list
     printf("   > Discovered Unowned Devices\n");
     g_unown_cnt = printDevList(g_unown_list);
-
+#ifdef __WITH_TLS__
+    setDevProtocol(g_unown_list);
+#endif
     return 0;
 }
 
@@ -355,9 +464,37 @@ static int discoverOwnedDevices(void)
     // display the discovered owned list
     printf("   > Discovered Owned Devices\n");
     g_own_cnt = printDevList(g_own_list);
+#ifdef __WITH_TLS__
+    setDevProtocol(g_own_list);
+#endif
+    return 0;
+}
+
+#ifdef MULTIPLE_OWNER
+static int discoverMOTEnabledDevices(void)
+{
+    // delete owned device list before updating it
+    if(g_mot_enable_list)
+    {
+        OCDeleteDiscoveredDevices(g_mot_enable_list);
+        g_mot_enable_list = NULL;
+    }
+
+    // call |OCDiscoverOwnedDevices| API actually
+    printf("   Discovering Multiple Ownership Transfer Enabled Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverMultipleOwnerEnabledDevices(DISCOVERY_TIMEOUT, &g_mot_enable_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverMultipleOwnerEnalbedDevices API error");
+        return -1;
+    }
+
+    // display the discovered owned list
+    printf("   > Discovered Multiple Ownership Transfer Enabled Devices\n");
+    g_mot_enable_cnt = printDevList(g_mot_enable_list);
 
     return 0;
 }
+#endif //MULTIPLE_OWNER
 
 static int registerDevices(void)
 {
@@ -534,7 +671,7 @@ static int provisionCred(void)
 
     // display the CRED-provisioned result
     printf("   > Provisioned Selected Pairwise Crendentials\n");
-    printf("   > Please Check Device's Status for the Linked Result, with [33] Menu\n");
+    printf("   > Please Check Device's Status for the Linked Result, with [34] Menu\n");
 
     return 0;
 }
@@ -777,6 +914,198 @@ CKLST_ERROR:
     return -1;
 }
 
+static int saveAcl(void)
+{
+    // create ACL to save into local SVR DB
+    OicSecAcl_t* acl = NULL;
+    OicUuid_t uuid =   {.id={0}};
+    char strUuid[64] = {0};
+
+    printf("[1] Use a test UUID [11111111-2222-3333-4444-555555555555]\n");
+    printf("[2] Use a user input\n");
+    int sel_num = 0;
+    for( ; ; )
+    {
+        printf("   > Select Number, for Subject UUID of new ACE: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &sel_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(1 == sel_num)
+        {
+            OICStrcpy(strUuid, sizeof(strUuid), "11111111-2222-3333-4444-555555555555");
+            break;
+        }
+        else if(2 == sel_num)
+        {
+            printf("   > Input the UUID : ");
+            for(int ret=0; 1!=ret; )
+            {
+                ret = scanf("%64s", strUuid);
+                for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+            }
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+
+    printf("Selected Subject UUID : %s\n", strUuid);
+    OCStackResult rst = ConvertStrToUuid(strUuid, &uuid);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "ConvertStrToUuid API error: %d", rst);
+        goto SVACL_ERROR;
+    }
+
+    acl = createSimpleAcl(uuid);
+    if(!acl)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl error return");
+        goto SVACL_ERROR;
+    }
+
+    // call |OCSaveACL| API actually
+    rst = OCSaveACL(acl);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCSaveACL API error: %d", rst);
+        goto SVACL_ERROR;
+    }
+    OCDeleteACLList(acl);  // after here |acl| points nothing
+
+    // display the ACL-provisioned result
+    printf("   > Saved Selected ACL\n");
+
+    return 0;
+
+SVACL_ERROR:
+    OCDeleteACLList(acl);  // after here |acl| points nothing
+    return -1;
+}
+
+static int getCred(void)
+{
+    // check |own_list| for checking selected link status on PRVN DB
+    if(!g_own_list || 1>g_own_cnt)
+    {
+        printf("   > Owned Device List, to Check Linked Status on PRVN DB, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for checking selected link status on PRVN DB
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for Checking Linked Status on PRVN DB: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    // call |getDevInst| API actually
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
+    if(!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        goto PVACL_ERROR;
+    }
+    OCStackResult rst = OCGetCredResource((void*) g_ctx, dev, getCredCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGetCred API error: %d", rst);
+        goto PVACL_ERROR;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCGetCredResource callback error");
+        goto PVACL_ERROR;
+    }
+
+    // display the result of get credential
+    printf("   > Get Cred SUCCEEDED\n");
+
+    return 0;
+
+PVACL_ERROR:
+    return -1;
+}
+
+static int getAcl(void)
+{
+    // check |own_list| for checking selected link status on PRVN DB
+    if(!g_own_list || 1>g_own_cnt)
+    {
+        printf("   > Owned Device List, to Check Linked Status on PRVN DB, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for checking selected link status on PRVN DB
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for Checking Linked Status on PRVN DB: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    // call |getDevInst| API actually
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
+    if(!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        goto PVACL_ERROR;
+    }
+    OCStackResult rst = OCGetACLResource((void*) g_ctx, dev, getAclCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGetACLResource API error: %d", rst);
+
+        goto PVACL_ERROR;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCGetACLResource callback error");
+        goto PVACL_ERROR;
+    }
+
+    // display the result of get credential
+    printf("   > Get ACL SUCCEEDED\n");
+
+    return 0;
+
+PVACL_ERROR:
+    return -1;
+}
+
 static int unlinkPairwise(void)
 {
     // check |own_list| for unlinking pairwise devices
@@ -877,22 +1206,557 @@ static int removeDevice(void)
     return 0;
 }
 
-static OicSecAcl_t* createAcl(const int dev_num)
+static int removeDeviceWithUuid(void)
 {
-    if(0>=dev_num || g_own_cnt<dev_num)
+    char strUuid[64] = {0};
+    OicUuid_t revUuid;
+    printf("Input the UUID : ");
+    for(int ret=0; 1!=ret; )
     {
-        OIC_LOG(ERROR, TAG, "createAcl invalid parameters");
-        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
+        ret = scanf("%63s", strUuid);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                    // '0x20<=code' is character region
     }
-
-    // allocate memory for |acl| struct
-    printf("   **** Create ACL for the Selected Device[%d]\n", dev_num);
-    OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
-    if(!acl)
+    OCStackResult rst = ConvertStrToUuid(strUuid, &revUuid);
+    if(OC_STACK_OK != rst)
     {
-        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
-        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
+        OIC_LOG_V(ERROR, TAG, "ConvertStrToUuid API error: %d", rst);
+        return -1;
+    }
+
+    g_doneCB = false;
+    rst = OCRemoveDeviceWithUuid("RemoveDeviceWithUUID", DISCOVERY_TIMEOUT, &revUuid, removeDeviceCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCRemoveDeviceWithUuid API error: %d", rst);
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCRemoveDeviceWithUuid callback error");
+        return -1;
+    }
+
+    // display the removed result
+    printf("   > Removed %s Device\n", strUuid);
+    printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
+
+    return 0;
+}
+
+OCStackResult displayNumCB(void * ctx, uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN])
+{
+    OIC_LOG(INFO, TAG, "IN displayMutualVerifNumCB");
+    OC_UNUSED(ctx);
+    if (NULL != mutualVerifNum)
+    {
+        OIC_LOG(INFO, TAG, "############ mutualVerifNum ############");
+        OIC_LOG_BUFFER(INFO, TAG, mutualVerifNum, MUTUAL_VERIF_NUM_LEN);
+        OIC_LOG(INFO, TAG, "############ mutualVerifNum ############");
+        OIC_LOG(INFO, TAG, "OUT displayMutualVerifNumCB");
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "############ Confirm on the Server side ############");
+    }
+    return OC_STACK_OK;
+}
+
+OCStackResult confirmNumCB(void * ctx)
+{
+    OC_UNUSED(ctx);
+    for (;;)
+    {
+        int userConfirm;
+
+        printf("   > Press 1 if the mutual verification numbers are the same\n");
+        printf("   > Press 0 if the mutual verification numbers are not the same\n");
+
+        for (int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &userConfirm);
+            for (; 0x20<=getchar(); );  // for removing overflow garbage
+                                        // '0x20<=code' is character region
+        }
+        if (1 == userConfirm)
+        {
+            break;
+        }
+        else if (0 == userConfirm)
+        {
+            return OC_STACK_USER_DENIED_REQ;
+        }
+        printf("   Entered Wrong Number. Please Enter Again\n");
+    }
+    return OC_STACK_OK;
+}
+
+OCStackResult notifyInputStateCB(void * ctx)
+{
+    OC_UNUSED(ctx);
+
+    OIC_LOG(DEBUG, TAG, "IN notifyInputStateCB");
+    OIC_LOG(DEBUG, TAG, "User input Callback in progress");
+    OIC_LOG(DEBUG, TAG, "OUT notifyInputStateCB");
+
+    return OC_STACK_OK;
+}
+
+OicSecOxm_t selectOTMcb(const OicSecOxm_t* otmList, const uint32_t len)
+{
+    return otmList[len-1];
+}
+
+#ifdef MULTIPLE_OWNER
+static int changeMultipleOwnershipTrnasferMode(void)
+{
+    // check |own_list| for removing device
+    if(!g_own_list || 1>g_own_cnt)
+    {
+        printf("   > Owned Device List is Empty\n");
+        printf("   > Please Discover the Owned Devices, with [12] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for removing it
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for MOT Device: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    int mom = 0;
+    for( ; ; )
+    {
+        printf("   0. Disable Multuple Ownership Transfer\n");
+        printf("   1. Enable Multuple Ownership Transfer\n");
+        printf("   2. (Not Supported yet) Timely Enable Multuple Ownership Transfer\n");
+        printf("   > Enter Mode of Multuple Ownership Transfer : ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &mom);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0 <= dev_num && OIC_NUMBER_OF_MOM_TYPE > dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_own_list, dev_num);
+    if(OC_STACK_OK == OCChangeMOTMode(NULL, motDev, (OicSecMomType_t)dev_num, updateDoxmForMOTCB))
+    {
+        g_doneCB = false;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "OCChangeMOTMode API error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int selectMultipleOwnershipTrnasferMethod(void)
+{
+    // check |own_list| for removing device
+    if(!g_mot_enable_list || 1>g_mot_enable_cnt)
+    {
+        printf("   > Multiple Ownership Transfer Enabled Device List is Empty\n");
+        printf("   > Please Discover the Multiple Ownership Transfer Enabled Devices, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for removing it
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for MOT Device: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_mot_enable_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    const int preconfOxm = 4;
+    int oxm = 0;
+    for( ; ; )
+    {
+        printf("   %d. (Not Supported)\n", OIC_JUST_WORKS);
+        printf("   %d. Random PIN OxM\n", OIC_RANDOM_DEVICE_PIN);
+        printf("   %d. (Not Supported)\n", OIC_MANUFACTURER_CERTIFICATE);
+        printf("   %d. (Not Supported)\n", OIC_DECENTRALIZED_PUBLIC_KEY);
+        printf("   %d. Pre-Configured PIN OxM\n", OIC_PRECONFIG_PIN);
+        printf("   > Enter Number of  OxM for Multiple Ownership Transfer : ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &oxm);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(OIC_PRECONFIG_PIN == oxm || OIC_RANDOM_DEVICE_PIN == oxm)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mot_enable_list, dev_num);
+    if(OC_STACK_OK ==  OCSelectMOTMethod(NULL, motDev, (OicSecOxm_t)oxm, updateDoxmForMOTCB))
+    {
+        g_doneCB = false;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "OCSelectMOTMethod API error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int provisionPreconfigPIN()
+{
+    // check |own_list| for removing device
+    if(!g_mot_enable_list || 1>g_mot_enable_cnt)
+    {
+        printf("   > Multiple Ownership Transfer Enabled Device List is Empty\n");
+        printf("   > Please Discover the Multiple Ownership Transfer Enabled Devices, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for removing it
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for MOT Device: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_mot_enable_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    char preconfigPin[9] = {0};
+    printf("   > Input the PreconfigPin (e.g. 12341234) : ");
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%8s", preconfigPin);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                    // '0x20<=code' is character region
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mot_enable_list, dev_num);
+    if(OC_STACK_OK == OCProvisionPreconfigPin(NULL, motDev, preconfigPin, strlen(preconfigPin), provisionCredCB))
+    {
+        g_doneCB = false;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionPreconfigPin API error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int removeSubOwner(void)
+{
+    // check |g_mot_enable_list| for removing sub-owner
+    if (!g_mot_enable_list || 1 > g_mot_enable_cnt)
+    {
+        printf("   > Multiple Ownership Transfer Enabled Device List is Empty\n");
+        printf("   > Please Discover the Multiple Ownership Transfer Enabled Devices, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select resource server for removing sub-owner
+    int dev_num = 0;
+    for ( ; ; )
+    {
+        printf("   > Enter Device Number to remove sub-owner: ");
+        for (int ret = 0; 1 != ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20 <= getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if (0 < dev_num && g_mot_enable_cnt >= dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mot_enable_list, dev_num);
+    if (motDev && motDev->doxm && motDev->doxm->subOwners)
+    {
+        OicSecSubOwner_t* subOwner = motDev->doxm->subOwners;
+        int so_cnt = 0;
+        while(subOwner)
+        {
+            printf("     [%zu] ", ++so_cnt);
+            printUuid(&subOwner->uuid);
+            printf("\n");
+            subOwner = subOwner->next;
+        }
+
+        int so_num = 0;
+        for ( ; ; )
+        {
+            printf("   > Enter SubOwner Number to be removed : ");
+            for (int ret = 0; 1 != ret; )
+            {
+                ret = scanf("%d", &so_num);
+                for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                            // '0x20<=code' is character region
+            }
+            if (0 < so_num && so_cnt >= so_num)
+            {
+                int target_num = 0;
+                subOwner = motDev->doxm->subOwners;
+                while (subOwner)
+                {
+                    if(so_num == ++target_num)
+                    {
+                        if (OC_STACK_OK != OCRemoveSubOwner(NULL, motDev, &subOwner->uuid, deleteDoxmForMOTCB))
+                        {
+                            return -1;
+                        }
+
+                        g_doneCB = false;
+
+                        if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+                        {
+                            OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+                            return -1;
+                        }
+                        return 0;
+                    }
+                    subOwner = subOwner->next;
+                }
+                break;
+            }
+            printf("     Entered Wrong Number. Please Enter Again\n");
+        }
+    }
+    else
+    {
+        printf("     SubOwner list is empty.\n");
+    }
+
+    return 0;
+}
+
+static int removeAllSubOwner(void)
+{
+    // check |g_mot_enable_list| for removing sub-owner
+    if (!g_mot_enable_list || 1 > g_mot_enable_cnt)
+    {
+        printf("   > Multiple Ownership Transfer Enabled Device List is Empty\n");
+        printf("   > Please Discover the Multiple Ownership Transfer Enabled Devices, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select resource server for removing sub-owner
+    int dev_num = 0;
+    for ( ; ; )
+    {
+        printf("   > Enter Device Number to remove sub-owner: ");
+        for (int ret = 0; 1 != ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20 <= getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if (0 < dev_num && g_mot_enable_cnt >= dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mot_enable_list, dev_num);
+    if (motDev && motDev->doxm && motDev->doxm->subOwners)
+    {
+        if (OC_STACK_OK != OCRemoveAllSubOwner(NULL, motDev, deleteDoxmForMOTCB))
+        {
+            return -1;
+        }
+
+        g_doneCB = false;
+
+        if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+        {
+            OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+            return -1;
+        }
+        return 0;
+    }
+    else
+    {
+        printf("     SubOwner list is empty.\n");
+    }
+
+    return 0;
+}
+
+#endif //MULTIPLE_OWNER
+
+static int resetDevice(void)
+{
+    // check |own_list| for removing device
+    if (!g_own_list || 1 > g_own_cnt)
+    {
+        printf("   > Owned Device List, to Reset Device, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;
+    }
+
+    OCProvisionDev_t *dev = NULL;
+
+    for ( ; ; )
+    {
+            printf("************************************************************\n");
+            printf("Reset device candidate list:\n");
+            g_unown_cnt = printDevList(g_own_list);
+            if(0 == g_unown_cnt)
+            {
+                break;
+            }
+
+            printf("Select number device from list\nor: -1 - escape\n");
+            int c = 0;
+
+            if (!scanf("%d",&c))
+            {
+                continue;
+            }
+
+            if(0 == c && NULL != dev)
+            {
+                break;
+            }
+
+            if(-1 == c)
+            {
+                return 0;
+            }
+
+            if(c > g_own_cnt)
+            {
+                continue;
+            }
+
+            dev = g_own_list;
+            for(int lst_cnt = 1; dev && lst_cnt != c; lst_cnt++, dev = dev->next);
+            break;
+
+    }
+
+    g_doneCB = false;
+    printf("   Resetting Selected Owned Device..\n");
+
+    OCStackResult rst = SRPResetDevice(dev, resetDeviceCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCResetDevice API error: %d", rst);
+        return -1;
+    }
+
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: callback error", __func__);
+        return -1;
+    }
+
+    // display the removed result
+    printf("   > Reset Selected Owned Device SUCCEEDED\n");
+    printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
+
+    return 0;
+}
+
+static int resetSVRDB(void)
+{
+    printf("   Resetting SVR DB..\n");
+    OCStackResult rst = OCResetSVRDB();
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCResetSVRDB API error: %d", rst);
+        return -1;
+    }
+    return 0;
+}
+
+static OicSecAcl_t* createAcl(const int dev_num)
+{
+    if(0>=dev_num || g_own_cnt<dev_num)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl invalid parameters");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
+    }
+
+    // allocate memory for |acl| struct
+    printf("   **** Create ACL for the Selected Device[%d]\n", dev_num);
+    OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
+    if(!acl)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
+    }
+    OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
+    if(!ace)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
     }
+    LL_APPEND(acl->aces, ace);
 
     // enter |subject| device number
     int num = 0;
@@ -918,7 +1782,7 @@ static OicSecAcl_t* createAcl(const int dev_num)
         OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
         goto CRACL_ERROR;
     }
-    memcpy(&acl->subject, &dev->doxm->deviceID, UUID_LENGTH);
+    memcpy(&ace->subjectuuid, &dev->doxm->deviceID, UUID_LENGTH);
 
     // enter number of |resources| in 'accessed' device
     for( ; ; )
@@ -942,17 +1806,18 @@ static OicSecAcl_t* createAcl(const int dev_num)
     // enter actually each 'accessed' |resources| name
     printf("         Enter Each Accessed Resource Name (each under 128 char)\n");
             // '128' is ACL_RESRC_MAX_LEN
-    acl->resourcesLen = (unsigned) num;
-    acl->resources = (char**) OICCalloc(acl->resourcesLen, sizeof(char*));
-    if(!acl->resources)
-    {
-        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
-        goto CRACL_ERROR;
-    }
+
     char rsrc_in[ACL_RESRC_MAX_LEN+1] = {0};  // '1' for null termination
-    for(int i=0; acl->resourcesLen>(unsigned)i; ++i)
+    for(int i = 0; num > i; ++i)
     {
-        printf("         Enter Accessed Resource[%d] Name: ", i+1);
+        OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
+        if(!rsrc)
+        {
+            OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+            goto CRACL_ERROR;
+        }
+
+        printf("         Enter Accessed Resource[%d] Name: (e.g. /a/led)", i+1);
         for(int ret=0; 1!=ret; )
         {
             ret = scanf("%128s", rsrc_in);  // '128' is ACL_RESRC_MAX_LEN
@@ -960,14 +1825,98 @@ static OicSecAcl_t* createAcl(const int dev_num)
                                         // '0x20<=code' is character region
         }
         size_t len = strlen(rsrc_in)+1;  // '1' for null termination
-        char* rsrc = (char*) OICCalloc(len, sizeof(char));
-        if(!rsrc)
+        rsrc->href = (char*) OICCalloc(len, sizeof(char));
+        if(!rsrc->href)
+        {
+            OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+            goto CRACL_ERROR;
+        }
+        OICStrcpy(rsrc->href, len, rsrc_in);
+
+        size_t arrLen = 0;
+        while(1)
+        {
+            printf("         Enter Number of resource type for [%s] : ", rsrc->href);
+            for(int ret=0; 1!=ret; )
+            {
+                ret = scanf("%zu", &arrLen);
+                for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                            // '0x20<=code' is character region
+            }
+            if(ACL_RESRC_ARRAY_SIZE >= arrLen)
+            {
+                break;
+            }
+            printf("     Entered Wrong Number. Please Enter under %d Again\n", ACL_RESRC_ARRAY_SIZE);
+        }
+
+        rsrc->typeLen = arrLen;
+        rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
+        if(!rsrc->types)
+        {
+            OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+            goto CRACL_ERROR;
+        }
+
+        for(size_t i = 0; i < arrLen; i++)
+        {
+            printf("         Enter ResourceType[%zu] Name (e.g. core.led): ", i+1);
+            for(int ret=0; 1!=ret; )
+            {
+                ret = scanf("%128s", rsrc_in);  // '128' is ACL_RESRC_MAX_LEN
+                for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                            // '0x20<=code' is character region
+            }
+            rsrc->types[i] = OICStrdup(rsrc_in);
+            if(!rsrc->types[i])
+            {
+                OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
+                goto CRACL_ERROR;
+            }
+        }
+
+        while(1)
+        {
+            printf("         Enter Number of interface for [%s]: ", rsrc->href);
+            for(int ret=0; 1!=ret; )
+            {
+                ret = scanf("%zu", &arrLen);
+                for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                            // '0x20<=code' is character region
+            }
+            if(ACL_RESRC_ARRAY_SIZE >= arrLen)
+            {
+                break;
+            }
+            printf("     Entered Wrong Number. Please Enter under %d Again\n", ACL_RESRC_ARRAY_SIZE);
+        }
+
+        rsrc->interfaceLen = arrLen;
+        rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
+        if(!rsrc->interfaces)
         {
             OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
             goto CRACL_ERROR;
         }
-        OICStrcpy(rsrc, len, rsrc_in);
-        acl->resources[i] = rsrc;  // after here, |rsrc| points nothing
+
+        for(size_t i = 0; i < arrLen; i++)
+        {
+            printf("         Enter Interface[%zu] Name (e.g. oic.if.baseline): ", i+1);
+            for(int ret=0; 1!=ret; )
+            {
+                ret = scanf("%128s", rsrc_in);  // '128' is ACL_RESRC_MAX_LEN
+                for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                            // '0x20<=code' is character region
+            }
+            rsrc->interfaces[i] = OICStrdup(rsrc_in);
+            if(!rsrc->interfaces[i])
+            {
+                OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
+                goto CRACL_ERROR;
+            }
+        }
+
+        LL_APPEND(ace->resources, rsrc);
     }
 
     // enter |permission| for this access
@@ -999,47 +1948,83 @@ static OicSecAcl_t* createAcl(const int dev_num)
         }
         pmsn_msk <<= 1;
     }
-    acl->permission = pmsn;
+    ace->permission = pmsn;
 
-    // enter |owner| device number
-    int own_num = 0;
-    for( ; ; )
+    return acl;
+
+CRACL_ERROR:
+    OCDeleteACLList(acl);  // after here |acl| points nothing
+    return NULL;
+}
+
+static OicSecAcl_t* createSimpleAcl(const OicUuid_t uuid)
+{
+    OIC_LOG(DEBUG, TAG, "createSimpleAcl IN");
+
+    // allocate memory for |acl| struct
+    OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
+    if(!acl)
     {
-        printf("   > [D] Enter Owner Device Number: ");
-        for(int ret=0; 1!=ret; )
-        {
-            ret = scanf("%d", &own_num);
-            for( ; 0x20<=getchar(); );  // for removing overflow garbages
-                                        // '0x20<=code' is character region
-        }
-        if(0<own_num && g_own_cnt>=own_num)
-        {
-            break;
-        }
-        printf("         Entered Wrong Number. Please Enter Again\n");
+        OIC_LOG(DEBUG, TAG, "OICCalloc error return");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
     }
-    acl->ownersLen = 1;
-    acl->owners = (OicUuid_t*) OICCalloc(1, sizeof(OicUuid_t));
-    if(!acl->owners)
+    OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
+    if(!ace)
     {
-        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
-        goto CRACL_ERROR;
+        OIC_LOG(DEBUG, TAG,  "OICCalloc error return");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
     }
+    LL_APPEND(acl->aces, ace);
 
-    dev = getDevInst((const OCProvisionDev_t*)g_own_list, own_num);
-    if(!dev || !dev->doxm)
+    memcpy(&ace->subjectuuid, &uuid, UUID_LENGTH);
+
+    OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
+    if(!rsrc)
     {
-        OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
-        goto CRACL_ERROR;
+        OIC_LOG(DEBUG, TAG, "OICCalloc error return");
+        OCDeleteACLList(acl);
+        return NULL;
     }
-    memcpy(acl->owners, &dev->doxm->deviceID, UUID_LENGTH);
-    printf("\n");
 
-    return acl;
+    char href[] = "*";
+    size_t len = strlen(href)+1;  // '1' for null termination
+    rsrc->href = (char*) OICCalloc(len, sizeof(char));
+    if(!rsrc->href)
+    {
+        OIC_LOG(DEBUG, TAG,  "OICCalloc error return");
+        OCDeleteACLList(acl);
+        return NULL;
+    }
+    OICStrcpy(rsrc->href, len, href);
 
-CRACL_ERROR:
-    OCDeleteACLList(acl);  // after here |acl| points nothing
-    return NULL;
+    size_t arrLen = 1;
+    rsrc->typeLen = arrLen;
+    rsrc->types = (char**)OICCalloc(arrLen, sizeof(char*));
+    if(!rsrc->types)
+    {
+        OIC_LOG(DEBUG, TAG,  "OICCalloc error return");
+        OCDeleteACLList(acl);
+        return NULL;
+    }
+    rsrc->types[0] = OICStrdup("");   // ignore
+
+    rsrc->interfaceLen = 1;
+    rsrc->interfaces = (char**)OICCalloc(arrLen, sizeof(char*));
+    if(!rsrc->interfaces)
+    {
+        OIC_LOG(DEBUG, TAG,  "OICCalloc error return");
+        OCDeleteACLList(acl);
+        return NULL;
+    }
+    rsrc->interfaces[0] = OICStrdup("oic.if.baseline");  // ignore
+
+    LL_APPEND(ace->resources, rsrc);
+
+    ace->permission = 31;   // R/W/U/D
+
+    OIC_LOG(DEBUG, TAG, "createSimpleAcl OUT");
+
+    return acl;
 }
 
 static OicSecPdAcl_t* createPdAcl(const int dev_num)
@@ -1202,6 +2187,20 @@ static FILE* fopen_prvnMng(const char* path, const char* mode)
     return fopen(SVR_DB_FILE_NAME, mode);
 }
 
+static int peerCertCallback(void *ctx, const mbedtls_x509_crt *cert, int depth)
+{
+    (void)ctx;
+
+    OIC_LOG_V(DEBUG, TAG, "Depth : %d", depth);
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+    OIC_LOG(DEBUG, TAG, "***** Serial number of certificate is below *****");
+    OIC_LOG_BUFFER(DEBUG, TAG, cert->serial.p, cert->serial.len);
+    OIC_LOG(DEBUG, TAG, "***** Serial number of certificate is above *****");
+    OIC_LOG_V(DEBUG, TAG, "OUT%s", __func__);
+
+    return 0;
+}
+
 static int waitCallbackRet(void)
 {
     for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
@@ -1214,12 +2213,17 @@ static int waitCallbackRet(void)
         }
     }
 
+    if(!g_doneCB)
+    {
+        OCPDMCleanupForTimeout();
+    }
+
     return 0;
 }
 
 static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
 {
-    if(!a || !b || 2>=max || !str)
+    if(!a || !b || 2>max || !str)
     {
         return -1;
     }
@@ -1255,6 +2259,133 @@ static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
     return -1;
 }
 
+#ifdef __WITH_TLS__
+
+static void setDevProtocol(OCProvisionDev_t* lst)
+{
+    if(!lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return;
+    }
+
+    for( ; lst; )
+    {
+        if(2 == secure_protocol)
+        {
+            lst->connType &= ~CT_ADAPTER_IP; //reset IP flag
+            lst->connType |= CT_ADAPTER_TCP; //set TCP flag
+            lst->endpoint.adapter = OC_ADAPTER_TCP;
+            lst->endpoint.port = lst->tcpPort;
+            lst->securePort = lst->tcpPort;
+        }
+        lst = lst->next;
+    }
+}
+
+static void selectSecureProtocol()
+{
+    printf("   Select protocol\n");
+    printf("   1 - DTLS(Default)\n");
+    printf("   2 - TLS\n");
+
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%d",&secure_protocol);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+        // '0x20<=code' is character region
+    }
+
+    if(0 >= secure_protocol || 2 < secure_protocol)
+    {
+        secure_protocol = 1;
+    }
+
+    setDevProtocol(g_own_list);
+    setDevProtocol(g_unown_list);
+}
+#endif
+
+static void secureStorageHwEmulation()
+{
+    printf("   Enable Secure Storage HW Emulation\n");
+
+    printf("         Enter Own Certificate File Path[~4095]: ");
+    char cert_filepath[4096] = {0,};
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%255s", cert_filepath);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                    // '0x20<=code' is character region
+    }
+
+    printf("         Enter Private Key File Path[~4095]: ");
+    char key_filepath[4096] = {0,};
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%255s", key_filepath);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                    // '0x20<=code' is character region
+    }
+
+    printf("         Enter Password for Key Password[~31][Press (Enter) to not set]: ");
+    char pwd[32] = {0,};
+    for(int i=0; i < 31; i++)
+    {
+        pwd[i] = (char)getchar();
+        if (0x20 <= pwd[i])
+        {
+            pwd[i--] = '\0';
+            continue;
+        }
+        if (0x0A == pwd[i])
+        {
+            pwd[i] = '\0';
+            break;
+        }
+    }
+
+    if (0 != SSemulSetCertkeyFilepath(cert_filepath, key_filepath, pwd))
+    {
+        printf("    Fail to set cert/key file path");
+        return;
+    }
+
+    if (0 != SetHwPkixCallbacks(HWGetKeyContext,
+                                                  HWFreeKeyContext,
+                                                  HWGetOwnCertificateChain,
+                                                  HWSetupPkContext))
+    {
+        printf("    Fail to regist HW Pkix Callbacks");
+        return;
+    }
+    printf("    Success to regist HW Pkix Callbacks");
+}
+
+static void selectVerifMethod()
+{
+    int option;
+    printf("   Select verification method for ownership transfer\n");
+    printf("   0 - No verification\n");
+    printf("   1 - Display only\n");
+    printf("   2 - Confirm only\n");
+    printf("   3 - Both Display and Confirm\n");
+
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%d",&option);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+        // '0x20<=code' is character region
+    }
+
+    if(0 > option || 3 < option)
+    {
+        printf("Invalid option!");
+    }
+    SetVerifyOption((VerifyOptionBitmask_t) option);
+    printf("Option %d chosen!", option);
+}
+
 static void printMenu(void)
 {
     printf("************************************************************\n");
@@ -1264,7 +2395,12 @@ static void printMenu(void)
     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
     printf("** 10. Discover All Un/Owned Devices on Network\n");
     printf("** 11. Discover Only Unowned Devices on Network\n");
+#ifdef MULTIPLE_OWNER
+    printf("** 12. Discover Only Owned Devices on Network\n");
+    printf("** 13. Discover Multiple Ownership Transfer Enabled Devices on Network\n\n");
+#else
     printf("** 12. Discover Only Owned Devices on Network\n\n");
+#endif //MULTIPLE_OWNER
 
     printf("** [B] REGISTER/OWN ALL DISCOVERED UNOWNED DEVICES\n");
     printf("** 20. Register/Own All Discovered Unowned Devices\n\n");
@@ -1274,15 +2410,42 @@ static void printMenu(void)
     printf("** 31. Provision Credentials for Pairwise Things\n");
     printf("** 32. Provision the Selected Access Control List(ACL)\n");
     printf("** 33. Provision Direct-Pairing Configuration\n");
-    printf("** 34. Check Linked Status of the Selected Device on PRVN DB\n\n");
+    printf("** 34. Check Linked Status of the Selected Device on PRVN DB\n");
+    printf("** 35. Save the Selected Access Control List(ACL) into local SVR DB\n\n");
 
     printf("** [D] UNLINK PAIRWISE THINGS\n");
     printf("** 40. Unlink Pairwise Things\n\n");
 
     printf("** [E] REMOVE THE SELECTED DEVICE\n");
-    printf("** 50. Remove the Selected Device\n\n");
+    printf("** 50. Remove the Selected Device\n");
+    printf("** 51. Remove Device with UUID (UUID input is required)\n");
+    printf("** 52. Reset the Selected Device\n");
+    printf("** 53. Reset SVR DB\n\n");
+
+    printf("** [F] GET SECURITY RESOURCE FOR DEBUGGING ONLY\n");
+    printf("** 60. Get the Credential resources of the Selected Device\n");
+    printf("** 61. Get the ACL resources of the Selected Device\n\n");
+
+#ifdef MULTIPLE_OWNER
+    printf("** [G] UPDATE THE MULTIPLE OWNERSHIP TRANSFER RELATED VALUE\n");
+    printf("** 70. Change the Multiple Ownership transfer MODE(update mom)\n");
+    printf("** 71. Provision Preconfigured PIN\n");
+    printf("** 72. Change the Multiple Ownership transfer METHOD(update oxmsel)\n");
+    printf("** 73. Remove Sub-Owner from Resource Server\n");
+    printf("** 74. Remove All Sub-Owner from Resource Server\n\n");
+#endif //MULTIPLE_OWNER
+
+#ifdef __WITH_TLS__
+    printf("** [H] SELECT SECURE PROTOCOL DTLS/TLS AND OTHERS\n");
+    printf("** 80. Select secure protocol(default DTLS)\n");
+    printf("** 81. Select verification method\n");
+    printf("** 82. Enable secure storage hw emulation\n\n");
+#else
+    printf("** [H] SELECT VERIFICATION OPTION\n");
+    printf("** 81. Select verification method\n\n");
+#endif
+    printf("** [I] EXIT PROVISIONING CLIENT\n");
 
-    printf("** [F] EXIT PROVISIONING CLIENT\n");
     printf("** 99. Exit Provisionong Client\n\n");
 
     printf("************************************************************\n\n");
@@ -1308,6 +2471,35 @@ static void printUsage(void)
 }
 #endif
 
+/**
+ * Sample implementation of Export key block and master secret
+ *
+ * @param[in] p_expkey  Context for the callback
+ * @aram[in] ms        Pointer to master secret (fixed length: 48 bytes)
+ * @param[in] kb        Pointer to key block, see RFC 5246 section 6.3
+ *                  (variable length: 2 * maclen + 2 * keylen + 2 * ivlen).
+ * @param[in] maclen    MAC length
+ * @param[in] keylen    Key length
+ * @param[in] ivlen     IV length
+ */
+static void SslExportKeysCallback(const unsigned char* masterSecret,
+                                  const unsigned char* keyBlock,
+                                  size_t macLen, size_t keyLen, size_t ivLen)
+{
+    OIC_LOG_V(INFO, TAG, "In %s ", __func__);
+
+    OIC_LOG(INFO, TAG, "[MASTER SECRET] : ");
+    OIC_LOG_BUFFER(INFO, TAG, masterSecret, 48);
+
+    OIC_LOG(INFO, TAG, "[KEY BLOCK] : ");
+    OIC_LOG_BUFFER(INFO, TAG, keyBlock, (2 * macLen) + (2 * keyLen) + (2 * ivLen));
+
+    OIC_LOG_V(INFO, TAG, "Mac Length = %zu, Key Length = %zu, IV Length = %zu",
+            macLen, keyLen, ivLen);
+
+    OIC_LOG_V(INFO, TAG, "Out %s ", __func__);
+}
+
 // main function for provisioning client using C-level provisioning API
 int main()
 {
@@ -1318,6 +2510,32 @@ int main()
         goto PMCLT_ERROR;
     }
 
+    if (CA_STATUS_OK !=
+        CASetSslExportKeysCallback(SslExportKeysCallback, CA_SSL_EKCB_DTLS, CA_SSL_EKCB_CLIENT))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to register the (D)TLS export Key Callback!");
+        goto PMCLT_ERROR;
+    }
+
+    // Client can choose a allowed/not-allowed OxM method.
+    if(OC_STACK_OK != OCSetOxmAllowStatus(OIC_DECENTRALIZED_PUBLIC_KEY, false))
+    {
+        OIC_LOG(WARNING, TAG, "Failed to disable OIC_DECENTRALIZED_PUBLIC_KEY OxM");
+    }
+
+    // set callbacks for verification options
+    SetDisplayNumCB(NULL, displayNumCB);
+    SetUserConfirmCB(NULL, confirmNumCB);
+    SetInputStateCB(NULL, notifyInputStateCB);
+    SetSelectOTMCB(selectOTMcb);
+
+    // set callback for checking peer certificate information
+    OCSetPeerCertCallback(NULL, peerCertCallback);
+
+#ifdef MULTIPLE_OWNER
+    SetPreconfigPin("12341234", 8);
+#endif //MULTIPLE_OWNER
+
     // main loop for provisioning manager
     int mn_num = 0;
     for( ; ; )
@@ -1352,6 +2570,14 @@ int main()
                 OIC_LOG(ERROR, TAG, "_12_DISCOV_OWN_DEVS_: error");
             }
             break;
+#ifdef MULTIPLE_OWNER
+        case _13_MOT_DISCOV_DEV_:
+            if(discoverMOTEnabledDevices())
+            {
+                OIC_LOG(ERROR, TAG, "_13_MOT_DISCOV_DEV_: error");
+            }
+            break;
+#endif //MULTIPLE_OWNER
         case _20_REGIST_DEVS_:
             if(registerDevices())
             {
@@ -1388,6 +2614,12 @@ int main()
                 OIC_LOG(ERROR, TAG, "_34_CHECK_LINK_STATUS_: error");
             }
             break;
+        case _35_SAVE_ACL_:
+            if(saveAcl())
+            {
+                OIC_LOG(ERROR, TAG, "_35_SAVE_ACL_: error");
+            }
+            break;
         case _40_UNLINK_PAIR_DEVS_:
             if(unlinkPairwise())
             {
@@ -1400,6 +2632,79 @@ int main()
                 OIC_LOG(ERROR, TAG, "_50_REMOVE_SELEC_DEV_: error");
             }
             break;
+        case _51_REMOVE_DEV_WITH_UUID_:
+            if(removeDeviceWithUuid())
+            {
+                OIC_LOG(ERROR, TAG, "_51_REMOVE_DEV_WITH_UUID_: error");
+            }
+            break;
+        case _52_RESET_SELEC_DEV_:
+            if(resetDevice())
+            {
+                OIC_LOG(ERROR, TAG, "_52_RESET_SELEC_DEV_: error");
+            }
+            break;
+        case _53_RESET_SVR_DB_:
+            if(resetSVRDB())
+            {
+                OIC_LOG(ERROR, TAG, "_53_RESET_SVR_DB_: error");
+            }
+            break;
+        case _60_GET_CRED_:
+            if(getCred())
+            {
+                OIC_LOG(ERROR, TAG, "_60_GET_CRED_: error");
+            }
+            break;
+        case _61_GET_ACL_:
+            if(getAcl())
+            {
+                OIC_LOG(ERROR, TAG, "_61_GET_ACL_: error");
+            }
+            break;
+#ifdef MULTIPLE_OWNER
+        case _70_MOT_CHANGE_MOM_:
+            if(changeMultipleOwnershipTrnasferMode())
+            {
+                OIC_LOG(ERROR, TAG, "_70_MOT_CHANGE_MOM_: error");
+            }
+            break;
+        case _71_MOT_PROV_PRECONF_PIN_:
+            if(provisionPreconfigPIN())
+            {
+                OIC_LOG(ERROR, TAG, "_71_MOT_PROV_PRECONF_PIN_: error");
+            }
+            break;
+        case _72_MOT_OXM_SEL_:
+            if(selectMultipleOwnershipTrnasferMethod())
+            {
+                OIC_LOG(ERROR, TAG, "_72_MOT_OXM_SEL_: error");
+            }
+            break;
+        case _73_MOT_REMOVE_SUBOWNER_:
+            if(removeSubOwner())
+            {
+                OIC_LOG(ERROR, TAG, "_73_MOT_REMOVE_SUBOWNER_ : error");
+            }
+            break;
+        case _74_MOT_REMOVE_ALL_SUBOWNER_:
+            if(removeAllSubOwner())
+            {
+                OIC_LOG(ERROR, TAG, "_74_MOT_REMOVE_ALL_SUBOWNER_ : error");
+            }
+            break;
+#endif //MULTIPLE_OWNER
+#ifdef __WITH_TLS__
+        case  _80_SELECT_PROTOCOL_:
+            selectSecureProtocol();
+            break;
+#endif
+        case _81_SELECT_VERIF_METHOD_:
+            selectVerifMethod();
+            break;
+        case _82_SECURE_STORAGE_HW_EMULATION_:
+            secureStorageHwEmulation();
+            break;
         case _99_EXIT_PRVN_CLT_:
             goto PMCLT_ERROR;
         default:
@@ -1415,6 +2720,9 @@ PMCLT_ERROR:
     }
     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
+#ifdef MULTIPLE_OWNER
+    OCDeleteDiscoveredDevices(g_mot_enable_list);  // after here |g_motdev_list| points nothing
+#endif //MULTIPLE_OWNER
 
     if(g_svr_fname)
     {