replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / ownershiptransfermanager.c
index 5a06faf..fc7946b 100644 (file)
@@ -42,6 +42,8 @@
 #endif
 #include <stdbool.h>
 #include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
 
 #include "logger.h"
 #include "oic_malloc.h"
 #include "cacommon.h"
 #include "cainterface.h"
 #include "base64.h"
+#if defined (__TIZENRT__)
+#include <apps/netutils/cJSON.h>
+#else
 #include "cJSON.h"
-#include "global.h"
+#endif
 #include "utlist.h"
 #include "srmresourcestrings.h"
 #include "doxmresource.h"
 #include "oxmjustworks.h"
 #include "oxmrandompin.h"
 #include "oxmmanufacturercert.h"
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#include "secureresourceprovider.h"
+
+#ifdef MULTIPLE_OWNER
 #include "oxmpreconfpin.h"
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 #include "otmcontextlist.h"
 #include "pmtypes.h"
 #include "pmutility.h"
@@ -73,6 +80,8 @@
 #include "ocpayload.h"
 #include "payload_logging.h"
 #include "pkix_interface.h"
+#include "oxmverifycommon.h"
+#include "psinterface.h"
 
 #define TAG "OIC_OTM"
 
  * List of allowed oxm list.
  * All oxm methods are allowed as default.
  */
-static uint8_t g_OxmAllowStatus[OIC_OXM_COUNT] = {ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM, NOT_ALLOWED_OXM};
-
-/**
- * Variables for pointing the OTMContext to be used in the DTLS handshake result callback.
- */
-static OTMContext_t* g_otmCtx = NULL;
+#ifdef MULTIPLE_OWNER
+static uint8_t g_OxmAllowStatus[OXM_IDX_COUNT] = {ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM,
+                                                  ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM,
+                                                  NOT_ALLOWED_OXM};
+#else
+static uint8_t g_OxmAllowStatus[OXM_IDX_COUNT] = {ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM,
+                                                  ALLOWED_OXM, ALLOWED_OXM, NOT_ALLOWED_OXM};
+#endif
 
 OCStackResult OTMSetOTCallback(OicSecOxm_t oxm, OTMCallbackData_t* callbacks)
 {
@@ -98,11 +109,13 @@ OCStackResult OTMSetOTCallback(OicSecOxm_t oxm, OTMCallbackData_t* callbacks)
     OIC_LOG(INFO, TAG, "IN OTMSetOTCallback");
 
     VERIFY_NON_NULL(TAG, callbacks, ERROR);
-#ifdef _ENABLE_MULTIPLE_OWNER_
-    VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > oxm || OIC_PRECONFIG_PIN == oxm), ERROR);
+
+#ifdef MULTIPLE_OWNER
+    VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > oxm || OIC_PRECONFIG_PIN == oxm || OIC_MV_JUST_WORKS == oxm
+                    || OIC_CON_MFG_CERT == oxm), ERROR);
 #else
-    VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > oxm), ERROR);
-#endif //_ENABLE_MULTIPLE_OWNER_
+    VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > oxm || OIC_MV_JUST_WORKS == oxm || OIC_CON_MFG_CERT == oxm), ERROR);
+#endif // MULTIPLE_OWNER
 
     switch(oxm)
     {
@@ -127,14 +140,26 @@ OCStackResult OTMSetOTCallback(OicSecOxm_t oxm, OTMCallbackData_t* callbacks)
     case OIC_DECENTRALIZED_PUBLIC_KEY:
         OIC_LOG(ERROR, TAG, "OIC_DECENTRALIZED_PUBLIC_KEY not supported yet.");
         return OC_STACK_INVALID_METHOD;
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
     case OIC_PRECONFIG_PIN:
         callbacks->loadSecretCB = LoadPreconfigPinCodeCallback;
         callbacks->createSecureSessionCB = CreateSecureSessionPreconfigPinCallback;
         callbacks->createSelectOxmPayloadCB = CreatePreconfigPinBasedSelectOxmPayload;
         callbacks->createOwnerTransferPayloadCB = CreatePreconfigPinBasedOwnerTransferPayload;
         break;
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
+    case OIC_MV_JUST_WORKS:
+        callbacks->loadSecretCB = LoadSecretJustWorksCallback;
+        callbacks->createSecureSessionCB = CreateSecureSessionJustWorksCallback;
+        callbacks->createSelectOxmPayloadCB = CreateMVJustWorksSelectOxmPayload;
+        callbacks->createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload;
+        break;
+    case OIC_CON_MFG_CERT:
+        callbacks->loadSecretCB = PrepareMCertificateCallback;
+        callbacks->createSecureSessionCB = CreateSecureSessionMCertificateCallback;
+        callbacks->createSelectOxmPayloadCB = CreateConMCertificateBasedSelectOxmPayload;
+        callbacks->createOwnerTransferPayloadCB = CreateMCertificateBasedOwnerTransferPayload;
+        break;
     default:
         OIC_LOG_V(ERROR, TAG, "Unknown OxM : %d", (int)oxm);
         return OC_STACK_INVALID_PARAM;
@@ -148,50 +173,119 @@ exit:
 }
 
 /**
+ * Internal API to convert OxM value to index of oxm allow table.
+ */
+static OxmAllowTableIdx_t GetOxmAllowTableIdx(OicSecOxm_t oxm)
+{
+    switch(oxm)
+    {
+        case OIC_JUST_WORKS:
+            return OXM_IDX_JUST_WORKS;
+        case OIC_RANDOM_DEVICE_PIN:
+            return OXM_IDX_RANDOM_DEVICE_PIN;
+        case OIC_MANUFACTURER_CERTIFICATE:
+            return OXM_IDX_MANUFACTURER_CERTIFICATE;
+        case OIC_DECENTRALIZED_PUBLIC_KEY:
+            return OXM_IDX_DECENTRALIZED_PUBLIC_KEY;
+        case OIC_MV_JUST_WORKS:
+            return OXM_IDX_MV_JUST_WORKS;
+        case OIC_CON_MFG_CERT:
+            return OXM_IDX_CON_MFG_CERT;
+#ifdef MULTIPLE_OWNER
+        case OIC_PRECONFIG_PIN:
+            return OXM_IDX_PRECONFIG_PIN;
+#endif
+        default:
+            return OXM_IDX_UNKNOWN;
+    }
+}
+
+/**
  * Function to select appropriate  provisioning method.
  *
  * @param[in] supportedMethods   Array of supported methods
  * @param[in] numberOfMethods   number of supported methods
  * @param[out]  selectedMethod         Selected methods
+ * @param[in] ownerType type of owner device (SUPER_OWNER or SUB_OWNER)
  * @return  OC_STACK_OK on success
  */
-static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethods,
-        size_t numberOfMethods, OicSecOxm_t *selectedMethod)
+OCStackResult OTMSelectOwnershipTransferMethod(const OicSecOxm_t *supportedMethods,
+        size_t numberOfMethods, OicSecOxm_t *selectedMethod, OwnerType_t ownerType)
 {
     bool isOxmSelected = false;
+    OxmAllowTableIdx_t selectedOxmIdx = OXM_IDX_UNKNOWN;
 
     OIC_LOG(DEBUG, TAG, "IN SelectProvisioningMethod");
 
-    if(numberOfMethods == 0 || !supportedMethods)
+    if (numberOfMethods == 0 || !supportedMethods)
     {
         OIC_LOG(WARNING, TAG, "Could not find a supported OxM.");
         return OC_STACK_ERROR;
     }
 
-    for(size_t i = 0; i < numberOfMethods; i++)
+    switch(ownerType)
     {
-        if(ALLOWED_OXM == g_OxmAllowStatus[supportedMethods[i]])
+        case SUPER_OWNER:
         {
-            *selectedMethod  = supportedMethods[i];
-            isOxmSelected = true;
-            break;
+            for (size_t i = 0; i < numberOfMethods; i++)
+            {
+                selectedOxmIdx = GetOxmAllowTableIdx(supportedMethods[i]);
+                if (OXM_IDX_COUNT <= selectedOxmIdx)
+                {
+                    OIC_LOG(WARNING, TAG, "Invalid oxm index to access OxM allow table");
+                    continue;
+                }
+
+#ifdef MULTIPLE_OWNER
+                if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx] &&
+                   OXM_IDX_PRECONFIG_PIN != selectedOxmIdx)
+#else
+                if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx])
+#endif //MULTIPLE_OWNER
+                {
+                    *selectedMethod  = supportedMethods[i];
+                    isOxmSelected = true;
+                }
+            }
+        }
+        break;
+#ifdef MULTIPLE_OWNER
+        case SUB_OWNER:
+        {
+            for (size_t i = 0; i < numberOfMethods; i++)
+            {
+                selectedOxmIdx = GetOxmAllowTableIdx(supportedMethods[i]);
+                if (OXM_IDX_COUNT <= selectedOxmIdx)
+                {
+                    OIC_LOG(WARNING, TAG, "Invalid oxm index to access OxM allow table");
+                    continue;
+                }
+
+                //in case of MOT, only Random PIN & Preconfigured PIN based OxM is allowed
+                if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx] &&
+                    (OXM_IDX_RANDOM_DEVICE_PIN == selectedOxmIdx ||
+                     OXM_IDX_PRECONFIG_PIN == selectedOxmIdx))
+                {
+                    *selectedMethod  = supportedMethods[i];
+                    isOxmSelected = true;
+                }
+            }
+        }
+        break;
+#endif
+        default:
+        {
+            OIC_LOG_V(ERROR, TAG, "Unknown owner type or Not supported owner type : %d", ownerType);
+            return OC_STACK_INVALID_PARAM;
         }
     }
-    if(!isOxmSelected)
+
+    if (!isOxmSelected)
     {
         OIC_LOG(ERROR, TAG, "Can not find the allowed OxM.");
         return OC_STACK_NOT_ALLOWED_OXM;
     }
 
-    for(size_t i = 0; i < numberOfMethods; i++)
-    {
-        if(*selectedMethod < supportedMethods[i] &&
-           ALLOWED_OXM == g_OxmAllowStatus[supportedMethods[i]])
-        {
-            *selectedMethod =  supportedMethods[i];
-        }
-    }
-
     OIC_LOG(DEBUG, TAG, "OUT SelectProvisioningMethod");
 
     return OC_STACK_OK;
@@ -223,6 +317,14 @@ static void SelectOperationMode(const OCProvisionDev_t *selectedDeviceInfo,
  */
 static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice);
 
+/*
+ * Internal function to setup & cleanup PDM to performing provisioning.
+ *
+ * @param[in] selectedDevice   selected device information to performing provisioning.
+ * @return  OC_STACK_OK on success
+ */
+static OCStackResult SetupPDM(const OCProvisionDev_t* selectedDevice);
+
 /**
  * Function to update owner transfer mode
  *
@@ -323,11 +425,12 @@ static bool IsComplete(OTMContext_t* otmCtx)
  * @param[in,out] otmCtx   Context value of ownership transfer.
  * @param[in] res   result of provisioning
  */
-static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
+void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
 {
     OIC_LOG_V(DEBUG, TAG, "IN SetResult : %d ", res);
 
-    if(NULL == otmCtx || NULL == otmCtx->selectedDeviceInfo)
+    if(NULL == otmCtx || NULL == otmCtx->selectedDeviceInfo
+            || NULL == otmCtx->selectedDeviceInfo->doxm)
     {
         OIC_LOG(WARNING, TAG, "OTMContext is NULL");
         return;
@@ -338,7 +441,6 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
                              otmCtx->selectedDeviceInfo->securePort))
     {
         OIC_LOG(WARNING, TAG, "Current OTM Process has already ended.");
-        return;
     }
 
     //Revert psk_info callback and new deivce uuid in case of random PIN OxM
@@ -351,7 +453,8 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
         OicUuid_t emptyUuid = { .id={0}};
         SetUuidForPinBasedOxm(&emptyUuid);
     }
-    else if(OIC_MANUFACTURER_CERTIFICATE == otmCtx->selectedDeviceInfo->doxm->oxmSel)
+    else if(OIC_MANUFACTURER_CERTIFICATE == otmCtx->selectedDeviceInfo->doxm->oxmSel ||
+                        OIC_CON_MFG_CERT == otmCtx->selectedDeviceInfo->doxm->oxmSel)
     {
         //Revert back certificate related callbacks.
         if(CA_STATUS_OK != CAregisterPkixInfoHandler(GetPkixInfo))
@@ -373,6 +476,17 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
             if(OC_STACK_OK != res && OC_STACK_CONTINUE != res && OC_STACK_DUPLICATE_REQUEST != res)
             {
                 otmCtx->ctxHasError = true;
+                if (OC_STACK_OK != PDMDeleteDevice(&otmCtx->ctxResultArray[i].deviceId))
+                {
+                    OIC_LOG(WARNING, TAG, "Internal error in PDMDeleteDevice");
+                }
+                CAEndpoint_t endpoint;
+                memcpy(&endpoint, &(otmCtx->selectedDeviceInfo->endpoint), sizeof(CAEndpoint_t));
+                endpoint.port = otmCtx->selectedDeviceInfo->securePort;
+                if (CA_STATUS_OK != CAcloseSslConnection(&endpoint))
+                {
+                    OIC_LOG(WARNING, TAG, "Failed to close Secure session");
+                }
             }
         }
     }
@@ -404,6 +518,23 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
     //If all OTM process is complete, invoke the user callback.
     if(IsComplete(otmCtx))
     {
+        if(OC_STACK_OK != res && OC_STACK_CONTINUE != res && OC_STACK_DUPLICATE_REQUEST != res)
+        {
+            // Reset doxm and pstat properties to pre-Ownership Transfer state
+            OIC_LOG(DEBUG, TAG, "Resetting doxm and pstat properties");
+            if(otmCtx->selectedDeviceInfo->doxm)
+            {
+                OicUuid_t emptyUuid = {.id = {0}};
+                memcpy(&(otmCtx->selectedDeviceInfo->doxm->owner), &emptyUuid, sizeof(OicUuid_t));
+                otmCtx->selectedDeviceInfo->doxm->owned = false;
+            }
+            if(otmCtx->selectedDeviceInfo->pstat)
+            {
+                otmCtx->selectedDeviceInfo->pstat->isOp = false;
+                otmCtx->selectedDeviceInfo->pstat->cm |= TAKE_OWNER;
+            }
+        }
+
         otmCtx->ctxResultCallback(otmCtx->userCtx, otmCtx->ctxResultArraySize,
                                    otmCtx->ctxResultArray, otmCtx->ctxHasError);
         OICFree(otmCtx->ctxResultArray);
@@ -430,6 +561,7 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
  */
 void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
 {
+    OIC_LOG(DEBUG, TAG, "IN DTLSHandshakeCB");
     if(NULL != endpoint && NULL != info)
     {
         OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
@@ -456,6 +588,59 @@ void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
                        false == newDevDoxm->owned &&
                        memcmp(&(newDevDoxm->owner), &emptyUuid, sizeof(OicUuid_t)) == 0)
                     {
+                        //In case of Mutual Verified Just-Works, display mutualVerifNum
+                        if (OIC_MV_JUST_WORKS == newDevDoxm->oxmSel)
+                        {
+                            uint8_t preMutualVerifNum[OWNER_PSK_LENGTH_128] = {0};
+                            uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN] = {0};
+                            OicUuid_t deviceID = {.id = {0}};
+
+                            //Generate mutualVerifNum
+                            char label[LABEL_LEN] = {0};
+                            snprintf(label, LABEL_LEN, "%s%s", MUTUAL_VERIF_NUM, OXM_MV_JUST_WORKS);
+                            res = GetDoxmDeviceID(&deviceID);
+                            if (OC_STACK_OK != res)
+                            {
+                                OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID");
+                                SetResult(otmCtx, res);
+                                return;
+                            }
+
+                            CAResult_t pskRet = CAGenerateOwnerPSK(endpoint,
+                                    (uint8_t *)label,
+                                    strlen(label),
+                                    deviceID.id, sizeof(deviceID.id),
+                                    newDevDoxm->deviceID.id, sizeof(newDevDoxm->deviceID.id),
+                                    preMutualVerifNum, OWNER_PSK_LENGTH_128);
+                            if (CA_STATUS_OK != pskRet)
+                            {
+                                OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential");
+                                SetResult(otmCtx, OC_STACK_ERROR);
+                                return;
+                            }
+
+                            memcpy(mutualVerifNum, preMutualVerifNum + OWNER_PSK_LENGTH_128 - sizeof(mutualVerifNum),
+                                    sizeof(mutualVerifNum));
+                            res = VerifyOwnershipTransfer(mutualVerifNum, DISPLAY_NUM);
+                            if (OC_STACK_OK != res)
+                            {
+                                OIC_LOG(ERROR, TAG, "Error while displaying mutualVerifNum");
+                                SetResult(otmCtx, res);
+                                return;
+                            }
+                        }
+                        //In case of confirmed manufacturer cert, display message
+                        else if (OIC_MANUFACTURER_CERTIFICATE == newDevDoxm->oxmSel || OIC_CON_MFG_CERT == newDevDoxm->oxmSel)
+                        {
+                            res = VerifyOwnershipTransfer(NULL, DISPLAY_NUM);
+                            if (OC_STACK_OK != res)
+                            {
+                                OIC_LOG(ERROR, TAG, "Error while displaying message");
+                                SetResult(otmCtx, res);
+                                return;
+                            }
+                        }
+
                         //Send request : POST /oic/sec/doxm [{... , "devowner":"PT's UUID"}]
                         res = PostOwnerUuid(otmCtx);
                         if(OC_STACK_OK != res)
@@ -488,19 +673,32 @@ void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
                             newDevDoxm->owned = false;
                             otmCtx->attemptCnt++;
 
-                            if(WRONG_PIN_MAX_ATTEMP > otmCtx->attemptCnt)
+                            RemoveOTMContext(otmCtx->selectedDeviceInfo->endpoint.addr,
+                                             otmCtx->selectedDeviceInfo->securePort);
+
+                            // In order to re-start ownership transfer, device information should be deleted from PDM.
+                            res = PDMDeleteDevice(&(otmCtx->selectedDeviceInfo->doxm->deviceID));
+                            if (OC_STACK_OK != res)
                             {
-                                res = StartOwnershipTransfer(otmCtx, otmCtx->selectedDeviceInfo);
-                                if(OC_STACK_OK != res)
-                                {
-                                    SetResult(otmCtx, res);
-                                    OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
-                                }
+                                SetResult(otmCtx, res);
+                                OIC_LOG(ERROR, TAG, "Failed to PDMDeleteDevice");
                             }
                             else
                             {
-                                OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts.");
-                                SetResult(otmCtx, OC_STACK_AUTHENTICATION_FAILURE);
+                                if(WRONG_PIN_MAX_ATTEMP > otmCtx->attemptCnt)
+                                {
+                                    res = StartOwnershipTransfer(otmCtx, otmCtx->selectedDeviceInfo);
+                                    if(OC_STACK_OK != res)
+                                    {
+                                        SetResult(otmCtx, res);
+                                        OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
+                                    }
+                                }
+                                else
+                                {
+                                    OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts.");
+                                    SetResult(otmCtx, OC_STACK_AUTHENTICATION_FAILURE);
+                                }
                             }
                         }
                         else
@@ -517,6 +715,7 @@ void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
             OIC_LOG(ERROR, TAG, "Can not find the OTM Context.");
         }
     }
+    OIC_LOG(DEBUG, TAG, "OUT DTLSHandshakeCB");
 }
 
 /**
@@ -546,7 +745,7 @@ static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
     }
 
     uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
-    OicSecKey_t ownerKey = {ownerPSK, OWNER_PSK_LENGTH_128};
+    OicSecKey_t ownerKey = {.data=ownerPSK, .len=OWNER_PSK_LENGTH_128, .encoding=OIC_ENCODING_RAW};
 
     //Generating OwnerPSK
     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
@@ -567,14 +766,9 @@ static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
         OICClearMemory(ownerPSK, sizeof(ownerPSK));
         VERIFY_NON_NULL(TAG, cred, ERROR);
 
-        // TODO: Added as workaround. Will be replaced soon.
-        cred->privateData.encoding = OIC_ENCODING_RAW;
-
-#if 1
-        // NOTE: Test codes to use BASE64 encoded owner PSK.
         uint32_t outSize = 0;
         size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1));
-        char* b64Buf = (uint8_t *)OICCalloc(1, b64BufSize);
+        char* b64Buf = (char *)OICCalloc(1, b64BufSize);
         VERIFY_NON_NULL(TAG, b64Buf, ERROR);
         b64Encode(cred->privateData.data, cred->privateData.len, b64Buf, b64BufSize, &outSize);
 
@@ -582,16 +776,15 @@ static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
         cred->privateData.data = (uint8_t *)OICCalloc(1, outSize + 1);
         VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
 
-        strncpy(cred->privateData.data, b64Buf, outSize);
+        strncpy((char*)(cred->privateData.data), b64Buf, outSize);
         cred->privateData.data[outSize] = '\0';
         cred->privateData.encoding = OIC_ENCODING_BASE64;
         cred->privateData.len = outSize;
         OICFree(b64Buf);
-#endif //End of Test codes
 
         //Finding previous ownerPSK.
         const OicSecCred_t* credList = GetCredList();
-        OicSecCred_t* prevCred = NULL;
+        const OicSecCred_t* prevCred = NULL;
         uint16_t credId = 0;
         LL_FOREACH(credList, prevCred)
         {
@@ -787,6 +980,22 @@ static OCStackApplicationResult OwnerUuidUpdateHandler(void *ctx, OCDoHandle UNU
     {
         if(otmCtx && otmCtx->selectedDeviceInfo)
         {
+            //In case of Mutual Verified Just-Works, wait for user confirmation
+            if (OIC_MV_JUST_WORKS == otmCtx->selectedDeviceInfo->doxm->oxmSel)
+            {
+                res = VerifyOwnershipTransfer(NULL, USER_CONFIRM);
+                if (OC_STACK_OK != res)
+                {
+                    if (OC_STACK_OK != SRPResetDevice(otmCtx->selectedDeviceInfo, otmCtx->ctxResultCallback))
+                    {
+                        OIC_LOG(WARNING, TAG, "OwnerUuidUpdateHandler : SRPResetDevice error");
+                    }
+                    OIC_LOG(ERROR, TAG, "OwnerUuidUpdateHandler:Failed to verify user confirm");
+                    SetResult(otmCtx, res);
+                    return OC_STACK_DELETE_TRANSACTION;
+                }
+            }
+
             res = SaveOwnerPSK(otmCtx->selectedDeviceInfo);
             if(OC_STACK_OK != res)
             {
@@ -808,8 +1017,25 @@ static OCStackApplicationResult OwnerUuidUpdateHandler(void *ctx, OCDoHandle UNU
     }
     else
     {
-        res = clientResponse->result;
-        OIC_LOG_V(ERROR, TAG, "OwnerUuidHandler : Unexpected result %d", res);
+        if (((OIC_MANUFACTURER_CERTIFICATE == otmCtx->selectedDeviceInfo->doxm->oxmSel) ||
+            (OIC_CON_MFG_CERT == otmCtx->selectedDeviceInfo->doxm->oxmSel)) &&
+                    OC_STACK_NOT_ACCEPTABLE == clientResponse->result)
+        {
+            res = OC_STACK_USER_DENIED_REQ;
+            OIC_LOG_V(ERROR, TAG,
+                    "OwnerUuidUpdateHandler : Denied Request(%d)", res);
+        }
+        else if (OC_STACK_GATEWAY_TIMEOUT == clientResponse->result)
+        {
+            res = clientResponse->result;
+            OIC_LOG_V(ERROR, TAG,
+                    "OwnerUuidUpdateHandler : Timeout:No Response Received(%d)", res);
+        }
+        else
+        {
+            res = clientResponse->result;
+            OIC_LOG_V(ERROR, TAG, "OwnerUuidUpdateHandler : Unexpected result(%d)", res);
+        }
         SetResult(otmCtx, res);
     }
 
@@ -819,6 +1045,49 @@ exit:
     return  OC_STACK_DELETE_TRANSACTION;
 }
 
+/*
+ * Invokes Callback to load Random PIN
+ */
+void *LoadRandomPin(void *ctx)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+    OTMContext_t* otmCtx = (OTMContext_t*)ctx;
+    OCStackResult res = OC_STACK_ERROR;
+    res = otmCtx->otmCallback.loadSecretCB(otmCtx);
+
+    if(OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Failed to load secret", __func__);
+        SetResult(otmCtx, res);
+        OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+        return NULL;
+    }
+
+    //Save the current context instance to use on the dtls handshake callback
+    if(OC_STACK_OK != AddOTMContext(otmCtx,
+                                     otmCtx->selectedDeviceInfo->endpoint.addr,
+                                     otmCtx->selectedDeviceInfo->securePort))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Failed to add OTM Context into OTM List.", __func__);
+        SetResult(otmCtx, res);
+        OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+        return NULL;
+    }
+
+    //Try DTLS handshake to generate secure session
+    if(otmCtx->otmCallback.createSecureSessionCB)
+    {
+        res = otmCtx->otmCallback.createSecureSessionCB(otmCtx);
+        if(OC_STACK_OK != res)
+        {
+            OIC_LOG_V(ERROR, TAG, "%s : Failed to create DTLS session", __func__);
+            SetResult(otmCtx, res);
+        }
+    }
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+    return NULL;
+}
+
 /**
  * Response handler for update operation mode.
  *
@@ -847,34 +1116,50 @@ static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle
         //Load secret for temporal secure session.
         if(otmCtx->otmCallback.loadSecretCB)
         {
-            res = otmCtx->otmCallback.loadSecretCB(otmCtx);
-            if(OC_STACK_OK != res)
+            if (OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel)
             {
-                OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret");
-                SetResult(otmCtx, res);
-                return  OC_STACK_DELETE_TRANSACTION;
+                pthread_t p_thread;
+                int thr_result;
+                thr_result = pthread_create(&p_thread, NULL, LoadRandomPin, (void *) otmCtx);
+                if (0 != thr_result)
+                {
+                    OIC_LOG_V(ERROR, TAG, "pthread_create Error with code %d", thr_result);
+                    SetResult(otmCtx, res);
+                    return  OC_STACK_DELETE_TRANSACTION;
+                }
+                OIC_LOG(INFO, TAG, "Random Pin loadSecretCB Thread Created");
             }
-        }
+            else
+            {
+                res = otmCtx->otmCallback.loadSecretCB(otmCtx);
+                if(OC_STACK_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret");
+                    SetResult(otmCtx, res);
+                    return  OC_STACK_DELETE_TRANSACTION;
+                }
 
-        //Save the current context instance to use on the dtls handshake callback
-        if(OC_STACK_OK != AddOTMContext(otmCtx,
-                                         otmCtx->selectedDeviceInfo->endpoint.addr,
-                                         otmCtx->selectedDeviceInfo->securePort))
-        {
-            OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to add OTM Context into OTM List.");
-            SetResult(otmCtx, res);
-            return OC_STACK_DELETE_TRANSACTION;
-        }
+                //Save the current context instance to use on the dtls handshake callback
+                if(OC_STACK_OK != AddOTMContext(otmCtx,
+                                                 otmCtx->selectedDeviceInfo->endpoint.addr,
+                                                 otmCtx->selectedDeviceInfo->securePort))
+                {
+                    OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to add OTM Context into OTM List.");
+                    SetResult(otmCtx, res);
+                    return OC_STACK_DELETE_TRANSACTION;
+                }
 
-        //Try DTLS handshake to generate secure session
-        if(otmCtx->otmCallback.createSecureSessionCB)
-        {
-            res = otmCtx->otmCallback.createSecureSessionCB(otmCtx);
-            if(OC_STACK_OK != res)
-            {
-                OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session");
-                SetResult(otmCtx, res);
-                return OC_STACK_DELETE_TRANSACTION;
+                //Try DTLS handshake to generate secure session
+                if(otmCtx->otmCallback.createSecureSessionCB)
+                {
+                    res = otmCtx->otmCallback.createSecureSessionCB(otmCtx);
+                    if(OC_STACK_OK != res)
+                    {
+                        OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session");
+                        SetResult(otmCtx, res);
+                        return OC_STACK_DELETE_TRANSACTION;
+                    }
+                }
             }
         }
     }
@@ -934,7 +1219,6 @@ static OCStackApplicationResult OwnerCredentialHandler(void *ctx, OCDoHandle UNU
              */
             // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
             caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
-
             if(CA_STATUS_OK != caResult)
             {
                 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
@@ -1228,12 +1512,13 @@ static OCStackResult PostOwnerCredential(OTMContext_t* otmCtx)
         memcpy(&(newCredential.subject), &credSubjectId, sizeof(OicUuid_t));
 
         //Fill private data as empty string
-        newCredential.privateData.data = "";
+        newCredential.privateData.data = (uint8_t*)"";
         newCredential.privateData.len = 0;
         newCredential.privateData.encoding = ownerCredential->privateData.encoding;
 
         newCredential.publicData.data = NULL;
         newCredential.publicData.len = 0;
+        newCredential.publicData.encoding = ownerCredential->publicData.encoding;
 
         int secureFlag = 0;
         //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
@@ -1694,92 +1979,151 @@ static OCStackResult PostUpdateOperationMode(OTMContext_t* otmCtx)
     return res;
 }
 
-static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice)
+static OCStackResult SetupPDM(const OCProvisionDev_t* selectedDevice)
 {
-    OIC_LOG(INFO, TAG, "IN StartOwnershipTransfer");
-    OCStackResult res = OC_STACK_INVALID_PARAM;
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
 
-    VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
-    VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
+    PdmDeviceState_t pdmState = PDM_DEVICE_UNKNOWN;
+    OCStackResult res = PDMGetDeviceState(&selectedDevice->doxm->deviceID, &pdmState);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Internal error in PDMGetDeviceState : %d", res);
+        return res;
+    }
 
-    OTMContext_t* otmCtx = (OTMContext_t*)ctx;
-    otmCtx->selectedDeviceInfo = selectedDevice;
+    char* strUuid = NULL;
+    bool removeCredReq = false;
+    if (OC_STACK_OK != ConvertUuidToStr(&selectedDevice->doxm->deviceID, &strUuid))
+    {
+        OIC_LOG(WARNING, TAG, "Failed to covert uuid to string");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    if (PDM_DEVICE_UNKNOWN == pdmState && !selectedDevice->doxm->owned)
+    {
+        removeCredReq = true;
+    }
+    else if (PDM_DEVICE_ACTIVE == pdmState && !selectedDevice->doxm->owned)
+    {
+        OIC_LOG_V(WARNING, TAG, "Unowned device[%s] dectected from PDM.", strUuid);
+        OIC_LOG_V(WARNING, TAG, "[%s] will be removed from PDM.", strUuid);
+        res = PDMDeleteDevice(&selectedDevice->doxm->deviceID);
+        if(OC_STACK_OK != res)
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to remove [%s] information from PDM.", strUuid);
+            goto exit;
+        }
+
+        removeCredReq = true;
+    }
+
+    if (removeCredReq)
+    {
+        OIC_LOG_V(WARNING, TAG, "[%s]'s credential will be removed.", strUuid);
+        res = RemoveCredential(&selectedDevice->doxm->deviceID);
+        if (OC_STACK_RESOURCE_DELETED != res)
+        {
+            OIC_LOG_V(WARNING, TAG, "Can not find [%s]'s credential.", strUuid);
+        }
+    }
 
     //Checking duplication of Device ID.
     bool isDuplicate = true;
     res = PDMIsDuplicateDevice(&selectedDevice->doxm->deviceID, &isDuplicate);
     if (OC_STACK_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Internal error in PDMIsDuplicateDevice");
-        return res;
+        OIC_LOG_V(ERROR, TAG, "Internal error in PDMIsDuplicateDevice : %d", res);
+        goto exit;
     }
+
     if (isDuplicate)
     {
-        PdmDeviceState_t state = PDM_DEVICE_UNKNOWN;
-        res = PDMGetDeviceState(&selectedDevice->doxm->deviceID, &state);
-        if(OC_STACK_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "Internal error in PDMGetDeviceState");
-            SetResult(otmCtx, res);
-            return res;
-        }
-
         char* strUuid = NULL;
         res = ConvertUuidToStr(&selectedDevice->doxm->deviceID, &strUuid);
-        if(OC_STACK_OK != res)
+        if (OC_STACK_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "Failed to convert UUID to str");
-            SetResult(otmCtx, res);
-            return res;
+            OIC_LOG_V(ERROR, TAG, "Failed to convert UUID to str : %d", res);
+            goto exit;
         }
 
-        if(PDM_DEVICE_STALE == state)
+        if (PDM_DEVICE_STALE == pdmState)
         {
             OIC_LOG(INFO, TAG, "Detected duplicated UUID in stale status, "
                                "device status will revert back to initial status.");
             res = PDMSetDeviceState(&selectedDevice->doxm->deviceID, PDM_DEVICE_INIT);
-            if(OC_STACK_OK != res)
+            if (OC_STACK_OK != res)
             {
-                OIC_LOG(ERROR, TAG, "Internal error in PDMSetDeviceState");
-                OICFree(strUuid);
-                SetResult(otmCtx, res);
-                return res;
+                OIC_LOG_V(ERROR, TAG, "Internal error in PDMSetDeviceState : %d", res);
+                goto exit;
             }
         }
-        else if(PDM_DEVICE_INIT == state)
+        else if (PDM_DEVICE_INIT == pdmState)
         {
             OIC_LOG_V(ERROR, TAG, "[%s]'s ownership transfer process is already started.", strUuid);
             OICFree(strUuid);
-            SetResult(otmCtx, OC_STACK_DUPLICATE_REQUEST);
-            return OC_STACK_OK;
+            res = OC_STACK_DUPLICATE_REQUEST;
+            goto exit;
         }
         else
         {
             OIC_LOG(ERROR, TAG, "Unknow device status while OTM.");
             OICFree(strUuid);
-            SetResult(otmCtx, OC_STACK_ERROR);
-            return OC_STACK_ERROR;
+            res = OC_STACK_ERROR;
+            goto exit;
         }
     }
     else
     {
         res = PDMAddDevice(&selectedDevice->doxm->deviceID);
-        if(OC_STACK_OK != res)
+        if (OC_STACK_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "Internal error in PDMAddDevice");
-            SetResult(otmCtx, res);
-            return res;
+            OIC_LOG_V(ERROR, TAG, "Internal error in PDMAddDevice : %d", res);
+            goto exit;
         }
     }
 
+exit:
+    OICFree(strUuid);
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+    return res;
+}
 
-    //Set to the lowest level OxM, and then find more higher level OxM.
-    res = SelectProvisioningMethod(selectedDevice->doxm->oxm,
-                                   selectedDevice->doxm->oxmLen,
-                                   &selectedDevice->doxm->oxmSel);
+static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice)
+{
+    OIC_LOG(INFO, TAG, "IN StartOwnershipTransfer");
+    OCStackResult res = OC_STACK_INVALID_PARAM;
+    OicUuid_t emptyOwner = {.id = {0} };
+
+    VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
+    VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
+
+    OTMContext_t* otmCtx = (OTMContext_t*)ctx;
+    otmCtx->selectedDeviceInfo = selectedDevice;
+
+    //If devowneruuid of selectedDevice is not emtry, PostOwnerUuid does not triggered in DTLSHandshakeCB
+    if (memcmp(&(selectedDevice->doxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)
+    {
+        OIC_LOG(DEBUG, TAG, "Set devowneruuid of selectedDevice to empty for OwnershipTransfer");
+        memcpy(&(selectedDevice->doxm->owner), &emptyOwner, sizeof(OicUuid_t));
+    }
+
+    //Setup PDM to perform the OTM, PDM will be cleanup if necessary.
+    res = SetupPDM(selectedDevice);
     if(OC_STACK_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Failed to select the provisioning method");
+        OIC_LOG_V(ERROR, TAG, "SetupPDM error : %d", res);
+        SetResult(otmCtx, res);
+        return res;
+    }
+
+    //Select the OxM to performing ownership transfer
+    res = OTMSelectOwnershipTransferMethod(selectedDevice->doxm->oxm,
+                                          selectedDevice->doxm->oxmLen,
+                                          &selectedDevice->doxm->oxmSel,
+                                          SUPER_OWNER);
+    if(OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to select the provisioning method : %d", res);
         SetResult(otmCtx, res);
         return res;
     }
@@ -1796,7 +2140,7 @@ static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selecte
     res = PostOwnerTransferModeToResource(otmCtx);
     if(OC_STACK_OK != res)
     {
-        OIC_LOG(WARNING, TAG, "Failed to select the provisioning method");
+        OIC_LOG_V(WARNING, TAG, "Failed to select the provisioning method : %d", res);
         SetResult(otmCtx, res);
         return res;
     }
@@ -1883,7 +2227,6 @@ OCStackResult OTMDoOwnershipTransfer(void* ctx,
     }
     pCurDev = selectedDevicelist;
 
-    OCStackResult res = OC_STACK_OK;
     //Fill the device UUID for result array.
     for(size_t devIdx = 0; devIdx < otmCtx->ctxResultArraySize; devIdx++)
     {
@@ -1894,14 +2237,10 @@ OCStackResult OTMDoOwnershipTransfer(void* ctx,
         pCurDev = pCurDev->next;
     }
 
-    StartOwnershipTransfer(otmCtx, selectedDevicelist);
+    OCStackResult res = StartOwnershipTransfer(otmCtx, selectedDevicelist);
 
     OIC_LOG(DEBUG, TAG, "OUT OTMDoOwnershipTransfer");
-    return OC_STACK_OK;
 
-error:
-    OICFree(otmCtx->ctxResultArray);
-    OICFree(otmCtx);
     return res;
 }
 
@@ -1910,12 +2249,22 @@ OCStackResult OTMSetOxmAllowStatus(const OicSecOxm_t oxm, const bool allowStatus
     OIC_LOG_V(INFO, TAG, "IN %s : oxm=%d, allow status=%s",
               __func__, oxm, (allowStatus ? "true" : "false"));
 
-    if(OIC_OXM_COUNT <= oxm)
+#ifdef MULTIPLE_OWNER
+    if(OIC_OXM_COUNT <= oxm && OIC_MV_JUST_WORKS != oxm && OIC_PRECONFIG_PIN != oxm && OIC_CON_MFG_CERT != oxm)
+#else
+    if(OIC_OXM_COUNT <= oxm && OIC_MV_JUST_WORKS != oxm && OIC_CON_MFG_CERT != oxm)
+#endif
     {
         return OC_STACK_INVALID_PARAM;
     }
 
-    g_OxmAllowStatus[oxm] = (allowStatus ? ALLOWED_OXM : NOT_ALLOWED_OXM);
+    OxmAllowTableIdx_t oxmIdx = GetOxmAllowTableIdx(oxm);
+    if(OXM_IDX_COUNT <= oxmIdx)
+    {
+        OIC_LOG(ERROR, TAG, "Invalid oxm index to access oxm allow table.");
+        return OC_STACK_ERROR;
+    }
+    g_OxmAllowStatus[oxmIdx] = (allowStatus ? ALLOWED_OXM : NOT_ALLOWED_OXM);
 
     OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
 
@@ -2037,3 +2386,97 @@ OCStackResult PostNormalOperationStatus(OTMContext_t* otmCtx)
 
     return ret;
 }
+
+OCStackResult ConfigSelfOwnership(void)
+{
+    OIC_LOG(INFO, TAG, "IN ConfigSelfOwnership");
+
+    bool isDeviceOwned = true;
+    if (OC_STACK_OK != GetDoxmIsOwned(&isDeviceOwned))
+    {
+        OIC_LOG (ERROR, TAG, "Unable to retrieve doxm owned state");
+        return OC_STACK_ERROR;
+    }
+    if( (true == isDeviceOwned) ||(true == GetPstatIsop()) )
+    {
+        OIC_LOG(ERROR, TAG, "The state of device is not Ready for Ownership transfer.");
+        return OC_STACK_ERROR;
+    }
+    OicUuid_t deviceID = {.id={0}};
+    if ( OC_STACK_OK != GetDoxmDeviceID(&deviceID) )
+    {
+        OIC_LOG (ERROR, TAG, "Unable to retrieve doxm Device ID");
+        return OC_STACK_ERROR;
+    }
+
+    OCStackResult ret = OC_STACK_OK;
+    //Update the pstat resource as Normal Operation.
+    ret = SetPstatSelfOwnership(&deviceID);
+    if(OC_STACK_OK != ret)
+    {
+        OIC_LOG (ERROR, TAG, "Unable to update pstat resource as Normal Operation");
+        goto exit;
+    }
+    //Update the doxm resource as Normal Operation.
+    ret = SetDoxmSelfOwnership(&deviceID);
+    if(OC_STACK_OK != ret)
+    {
+        OIC_LOG (ERROR, TAG, "Unable to update doxm resource as Normal Operation");
+        goto exit;
+    }
+    //Update default ACE of security resource to prevent anonymous user access.
+    ret = UpdateDefaultSecProvACE();
+    if(OC_STACK_OK != ret)
+    {
+        OIC_LOG (ERROR, TAG, "Unable to update default ace in ConfigSelfOwnership");
+        goto exit;
+    }
+    //Update the acl resource owner as owner device.
+    ret = SetAclRownerId(&deviceID);
+    if(OC_STACK_OK != ret)
+    {
+        OIC_LOG (ERROR, TAG, "Unable to update acl resource in ConfigSelfOwnership");
+        goto exit;
+    }
+    //Update the cred resource owner as owner device.
+    ret = SetCredRownerId(&deviceID);
+    if(OC_STACK_OK != ret)
+    {
+        // Cred resouce may be empty in Ready for Ownership transfer state.
+        if (OC_STACK_NO_RESOURCE == ret)
+        {
+            OIC_LOG (INFO, TAG, "Cred resource is empty");
+            ret = OC_STACK_OK;
+            goto exit;
+        }
+        OIC_LOG (ERROR, TAG, "Unable to update cred resource in ConfigSelfOwnership");
+    }
+
+exit:
+    if(OC_STACK_OK != ret)
+    {
+        /*
+         * If some error is occured while configure self-ownership,
+         * ownership related resource should be revert back to initial status.
+        */
+        ResetSecureResourceInPS();
+    }
+
+    return ret;
+}
+
+
+void OTMTerminate()
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    DeleteOTMContextList();
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+    if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL))
+    {
+        OIC_LOG(WARNING, TAG, "Failed to register (D)TLS handshake callback.");
+    }
+#endif // __WITH_DTLS__ or __WITH_TLS__
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+}