replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / security / src / doxmresource.c
index fa210a7..43aeb54 100644 (file)
 #include <strings.h>
 #endif
 
-#ifdef __WITH_DTLS__
-#include "global.h"
-#endif
-
 #include "ocstack.h"
 #include "oic_malloc.h"
 #include "payload_logging.h"
 #include "credresource.h"
 #include "srmutility.h"
 #include "pinoxmcommon.h"
+#include "oxmverifycommon.h"
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 #include "pkix_interface.h"
+#include "ca_adapter_net_ssl.h"
 #endif
 
 #define TAG  "OIC_SRM_DOXM"
@@ -66,6 +64,32 @@ static const uint16_t CBOR_SIZE = 512;
 /** Max cbor size payload. */
 static const uint16_t CBOR_MAX_SIZE = 4400;
 
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+/** MAX uuid seed size */
+#define MAX_UUID_SEED_SIZE (64)
+/** MIN uuid seed size */
+#define MIN_UUID_SEED_SIZE (8)
+
+/** Buffer to save the seed of device UUID */
+static uint8_t gUuidSeed[MAX_UUID_SEED_SIZE];
+static size_t gUuidSeedSize = 0;
+#endif
+
+#ifdef MULTIPLE_OWNER
+#define MAX_SUBOWNER_SIZE (64)
+#define MIN_SUBOWNER_SIZE (1)
+#define DEFAULT_SUBOWNER_SIZE (32)
+
+static size_t gMaxSubOwnerSize = DEFAULT_SUBOWNER_SIZE;
+#endif
+
+typedef enum ConfirmState{
+    CONFIRM_STATE_READY = 0,
+    CONFIRM_STATE_WAIT = 1,
+    CONFIRM_STATE_ACCEPTED = 2,
+    CONFIRM_STATE_DENIED = 3
+}ConfirmState_t;
+
 static OicSecDoxm_t        *gDoxm = NULL;
 static OCResourceHandle    gDoxmHandle = NULL;
 
@@ -82,13 +106,17 @@ static OicSecDoxm_t gDefaultDoxm =
     {.id = {0}},            /* OicUuid_t deviceID */
     false,                  /* bool dpc */
     {.id = {0}},            /* OicUuid_t owner */
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
     NULL,                   /* OicSecSubOwner_t sub-owner list */
     NULL,                   /* OicSecMomType_t multiple owner mode */
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
     {.id = {0}},            /* OicUuid_t rownerID */
 };
 
+static uint16_t gConfirmMsgId = 0;
+static ConfirmState_t gConfirmState = CONFIRM_STATE_READY;
+
+
 /**
  * This method is internal method.
  * the param roParsed is optionally used to know whether cborPayload has
@@ -111,7 +139,7 @@ void DeleteDoxmBinData(OicSecDoxm_t* doxm)
         //clean oxm
         OICFree(doxm->oxm);
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
         //clean mom
         OICFree(doxm->mom);
 
@@ -126,7 +154,7 @@ void DeleteDoxmBinData(OicSecDoxm_t* doxm)
                 OICFree(subowner);
             }
         }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 
         //Clean doxm itself
         OICFree(doxm);
@@ -240,7 +268,7 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz
         strUuid = NULL;
     }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
     //Device SubOwnerID -- Not Mandatory
     if(doxm->subOwners)
     {
@@ -281,7 +309,7 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz
         cborEncoderResult = cbor_encode_int(&doxmMap, (int64_t)doxm->mom->mode);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Value.");
     }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 
     //devownerid -- Mandatory
     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVOWNERID_NAME,
@@ -352,6 +380,7 @@ exit:
         OIC_LOG(DEBUG, TAG, "Memory getting reallocated.");
         // reallocate and try again!
         OICFree(outPayload);
+        outPayload = NULL;
         // Since the allocated initial memory failed, double the memory.
         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
         OIC_LOG_V(DEBUG, TAG, "Doxm reallocation size : %zd.", cborLen);
@@ -551,7 +580,7 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
         memcpy(doxm->owner.id, gDoxm->owner.id, sizeof(doxm->owner.id));
     }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_MOM_NAME, &doxmMap);
     if(CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
     {
@@ -625,7 +654,7 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
             LL_APPEND(doxm->subOwners, subOwnerId);
         }
     }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 
     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_ROWNERID_NAME, &doxmMap);
     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
@@ -712,10 +741,9 @@ static bool ValidateQuery(const char * query)
     bool bDeviceIDMatch = false;    // does 'deviceid' query matches with doxm.deviceid ?
     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
-#ifdef _ENABLE_MULTIPLE_OWNER_
-    bool bMotQry = false;         // does querystring contains 'mom' and 'owned' query ?
+#ifdef MULTIPLE_OWNER
     bool bMotMatch = false;       // does 'mom' query value is not '0' && does query value matches with doxm.owned status?
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 
     OicParseQueryIter_t parseIter = {.attrPos = NULL};
 
@@ -738,10 +766,9 @@ static bool ValidateQuery(const char * query)
             }
         }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_MOM_NAME, strlen(OIC_JSON_MOM_NAME)) == 0)
         {
-            bMotQry = true;
             OicSecMomType_t momMode = (OicSecMomType_t)(parseIter.valPos[0] - CHAR_ZERO);
             if(NULL != gDoxm->mom && momMode != gDoxm->mom->mode)
             {
@@ -759,7 +786,7 @@ static bool ValidateQuery(const char * query)
             }
             return bMotMatch;
         }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 
         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
         {
@@ -784,14 +811,8 @@ static bool ValidateQuery(const char * query)
         }
     }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
-    return ((bOwnedQry ? bOwnedMatch : true) &&
-            (bDeviceIDQry ? bDeviceIDMatch : true) &&
-            (bMotQry ? bMotMatch : true));
-#else
     return ((bOwnedQry ? bOwnedMatch : true) &&
             (bDeviceIDQry ? bDeviceIDMatch : true));
-#endif //_ENABLE_MULTIPLE_OWNER_
 }
 
 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
@@ -862,7 +883,7 @@ static void updateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst)
             dst->owned = src->owned;
         }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
         if(src->mom)
         {
             OIC_LOG(DEBUG, TAG, "dectected 'mom' property");
@@ -875,27 +896,74 @@ static void updateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst)
                 }
             }
         }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
     }
 }
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
+/**
+ * Internal function to get number of sub-owner
+ */
+static size_t GetSubOwnerSize()
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    size_t numberOfSubOwner = 0;
+
+    if (gDoxm && gDoxm->subOwners)
+    {
+        OicSecSubOwner_t* subowner = NULL;
+        LL_FOREACH(gDoxm->subOwners, subowner)
+        {
+            numberOfSubOwner++;
+        }
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Numer of registered sub-owner=%d", numberOfSubOwner);
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+
+    return numberOfSubOwner;
+}
+
 /**
  * Callback function to handle MOT DTLS handshake result.
- * @param[out]   object           remote device information.
+ * @param[out]   endpoint           remote device information.
  * @param[out]   errorInfo        CA Error information.
  */
-void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
+void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *endpoint,
                                 const CAErrorInfo_t *errorInfo)
 {
-    OIC_LOG(DEBUG, TAG, "IN MultipleOwnerDTLSHandshakeCB");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    if (!endpoint || !errorInfo)
+    {
+        OIC_LOG(ERROR, TAG, "Invalid param");
+        return;
+    }
+
+    if (!gDoxm)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: gDoxm is NULL", __func__);
+        return;
+    }
 
-    if(CA_STATUS_OK == errorInfo->result)
+    if ((CA_STATUS_OK == errorInfo->result) && (true == gDoxm->owned)
+        && (OIC_PRECONFIG_PIN == gDoxm->oxmSel) && (NULL != gDoxm->mom)
+        && (OIC_MULTIPLE_OWNER_DISABLE != gDoxm->mom->mode) && (CA_ADAPTER_TCP != endpoint->adapter))
     {
-        const CASecureEndpoint_t* authenticatedSubOwnerInfo = CAGetSecureEndpointData(object);
-        if(authenticatedSubOwnerInfo)
+        OIC_LOG_V(INFO, TAG, "DTLS session established for sub-owner authentication : (%s:%d)",
+                  endpoint->addr, endpoint->port);
+
+        const CASecureEndpoint_t* authenticatedSubOwnerInfo = CAGetSecureEndpointData(endpoint);
+        if (authenticatedSubOwnerInfo)
         {
+            if (0 == memcmp(authenticatedSubOwnerInfo->identity.id, gDoxm->owner.id,
+                            authenticatedSubOwnerInfo->identity.id_length))
+            {
+                OIC_LOG(WARNING, TAG, "Super owner tried MOT, this request will be ignored.");
+                return;
+            }
+
             OicSecSubOwner_t* subOwnerInst = NULL;
             LL_FOREACH(gDoxm->subOwners, subOwnerInst)
             {
@@ -907,19 +975,48 @@ void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
                 }
             }
 
-            if(NULL == subOwnerInst)
+            if (NULL == subOwnerInst)
             {
                 subOwnerInst = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
-                if(subOwnerInst)
+                if (subOwnerInst)
                 {
-                    OIC_LOG(DEBUG, TAG, "Adding New SubOwner");
-                    memcpy(subOwnerInst->uuid.id, authenticatedSubOwnerInfo->identity.id,
-                           authenticatedSubOwnerInfo->identity.id_length);
-                    LL_APPEND(gDoxm->subOwners, subOwnerInst);
-                    if(!UpdatePersistentStorage(gDoxm))
+                    char* strUuid = NULL;
+                    if (OC_STACK_OK != ConvertUuidToStr(&subOwnerInst->uuid, &strUuid))
                     {
-                        OIC_LOG(ERROR, TAG, "Failed to register SubOwner UUID into Doxm");
+                        OIC_LOG(WARNING, TAG, "ConvertUuidToStr error");
                     }
+                    OIC_LOG_V(DEBUG, TAG, "Adding New SubOwner(%s)", strUuid);
+
+                    if (gMaxSubOwnerSize > GetSubOwnerSize())
+                    {
+                        memcpy(subOwnerInst->uuid.id, authenticatedSubOwnerInfo->identity.id,
+                               authenticatedSubOwnerInfo->identity.id_length);
+                        LL_APPEND(gDoxm->subOwners, subOwnerInst);
+                        if (!UpdatePersistentStorage(gDoxm))
+                        {
+                            OIC_LOG(ERROR, TAG, "Failed to register SubOwner UUID into Doxm");
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Number of sub-owner exceeded : (MAX SIZE=%d)", gMaxSubOwnerSize);
+
+                        //Close DTLS session
+                        if (CA_STATUS_OK != CAcloseSslSession(endpoint))
+                        {
+                            OIC_LOG_V(ERROR, TAG, "CAcloseSslSession error for [%s:%d]", endpoint->addr, endpoint->port);
+                        }
+
+                        //Remove credential
+                        if (OC_STACK_RESOURCE_DELETED != RemoveCredential(&subOwnerInst->uuid))
+                        {
+                            OIC_LOG_V(ERROR, TAG, "RemoveCredential error for [%s]", strUuid);
+                        }
+
+                        // TODO: How to send error to client side?
+                    }
+
+                    OICFree(strUuid);
                 }
             }
         }
@@ -930,9 +1027,9 @@ void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
         OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler");
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT MultipleOwnerDTLSHandshakeCB");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 #endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 
 /**
@@ -980,6 +1077,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
     OicUuid_t emptyOwner = {.id = {0} };
     static uint16_t previousMsgId = 0;
+    bool isDuplicatedMsg = false;
 
     /*
      * Convert CBOR Doxm data into binary. This will also validate
@@ -995,6 +1093,34 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
         OCStackResult res = CBORPayloadToDoxmBin(payload, size, &newDoxm, &roParsed);
         if (newDoxm && OC_STACK_OK == res)
         {
+            /*
+             * message ID is supported for CoAP over UDP only according to RFC 7252
+             * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
+             * In case of other transport adapter, duplicate message check is not required.
+             */
+            if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
+                 previousMsgId == ehRequest->messageID)
+            {
+                isDuplicatedMsg = true;
+            }
+
+            if (isDuplicatedMsg && ehRequest->messageID == gConfirmMsgId)
+            {
+                if (CONFIRM_STATE_WAIT == gConfirmState)
+                {
+                    OIC_LOG(DEBUG, TAG, "Confirm callback already invoked.");
+                    OIC_LOG(DEBUG, TAG, "This request will be ignored.");
+                    DeleteDoxmBinData(newDoxm);
+                    return OC_EH_OK;
+                }
+                else
+                {
+                    OIC_LOG_V(DEBUG, TAG, "Confirm request already done, Confirm Result = %s", (CONFIRM_STATE_ACCEPTED == gConfirmState ? "ACCEPTED" : "DENIED"));
+                    ehRet = (CONFIRM_STATE_ACCEPTED == gConfirmState ? OC_EH_OK : OC_EH_NOT_ACCEPTABLE);
+                    goto exit;
+                }
+            }
+
             // Check request on RO property
             if (true == roParsed)
             {
@@ -1003,6 +1129,8 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                 goto exit;
             }
 
+            VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+
             // in owned state
             if (true == gDoxm->owned)
             {
@@ -1016,7 +1144,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                 updateWriteableProperty(newDoxm, gDoxm);
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
                 //handle mom
                 if(gDoxm->mom)
                 {
@@ -1029,7 +1157,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                             OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
-                            caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, ehRequest->devAddr.adapter);
+                            caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, ehRequest->devAddr.adapter);
                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                             OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
 
@@ -1077,7 +1205,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         LL_APPEND(gDoxm->subOwners, subowner);
                     }
                 }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 #endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 
                 //Update new state in persistent storage
@@ -1103,7 +1231,15 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                     goto exit;
                 }
 
-                if (OIC_JUST_WORKS == newDoxm->oxmSel)
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+                if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+                {
+                    InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+                                          NULL, OIC_OTM_STARTED);
+                }
+#endif
+
+                if (OIC_JUST_WORKS == newDoxm->oxmSel || OIC_MV_JUST_WORKS == newDoxm->oxmSel)
                 {
                     /*
                      * If current state of the device is un-owned, enable
@@ -1112,6 +1248,18 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                      */
                     if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
                     {
+                        gDoxm->oxmSel = newDoxm->oxmSel;
+                        //Update new state in persistent storage
+                        if ((UpdatePersistentStorage(gDoxm) == true))
+                        {
+                            ehRet = OC_EH_OK;
+                        }
+                        else
+                        {
+                            OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
+                            ehRet = OC_EH_ERROR;
+                            goto exit;
+                        }
                         OIC_LOG (INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
                         ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
@@ -1133,6 +1281,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         {
                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
                             ehRet = OC_EH_ERROR;
+                            goto exit;
                         }
 
                         /*
@@ -1144,6 +1293,59 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
+                        //In case of Mutual Verified Just-Works, verify mutualVerifNum
+                        if (OIC_MV_JUST_WORKS == newDoxm->oxmSel && false == newDoxm->owned &&
+                            false == isDuplicatedMsg)
+                        {
+                            uint8_t preMutualVerifNum[OWNER_PSK_LENGTH_128] = {0};
+                            uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN] = {0};
+                            OicUuid_t deviceID = {.id = {0}};
+
+                            //Generate mutualVerifNum
+                            OCServerRequest * request = GetServerRequestUsingHandle(ehRequest->requestHandle);
+
+                            char label[LABEL_LEN] = {0};
+                            snprintf(label, LABEL_LEN, "%s%s", MUTUAL_VERIF_NUM, OXM_MV_JUST_WORKS);
+                            if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))
+                            {
+                                OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID");
+                                ehRet = OC_EH_ERROR;
+                                goto exit;
+
+                            }
+
+                            CAResult_t pskRet = CAGenerateOwnerPSK((CAEndpoint_t *)&request->devAddr,
+                                    (uint8_t *)label,
+                                    strlen(label),
+                                    gDoxm->owner.id, sizeof(gDoxm->owner.id),
+                                    gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id),
+                                    preMutualVerifNum, OWNER_PSK_LENGTH_128);
+                            if (CA_STATUS_OK != pskRet)
+                            {
+                                OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential");
+                                ehRet = OC_EH_ERROR;
+                                goto exit;
+
+                            }
+
+                            memcpy(mutualVerifNum, preMutualVerifNum + OWNER_PSK_LENGTH_128 - sizeof(mutualVerifNum),
+                                    sizeof(mutualVerifNum));
+
+                            gConfirmMsgId = ehRequest->messageID;
+                            gConfirmState = CONFIRM_STATE_WAIT;
+                            //Wait for user confirmation
+                            if (OC_STACK_OK != VerifyOwnershipTransfer(mutualVerifNum, DISPLAY_NUM | USER_CONFIRM))
+                            {
+                                ehRet = OC_EH_NOT_ACCEPTABLE;
+                                gConfirmState = CONFIRM_STATE_DENIED;
+                            }
+                            else
+                            {
+                                ehRet = OC_EH_OK;
+                                gConfirmState = CONFIRM_STATE_ACCEPTED;
+                            }
+                        }
+
 #endif // __WITH_DTLS__ or __WITH_TLS__
                     }
                 }
@@ -1175,37 +1377,14 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
-                        caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256,
+                        caRes = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
                                                     ehRequest->devAddr.adapter);
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
 
-                        char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
-                         //TODO ehRequest->messageID for copa over TCP always is null. Find reason why.
-                        if(ehRequest->devAddr.adapter == OC_ADAPTER_IP && previousMsgId != ehRequest->messageID)
-                        {
-                            if(OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
-                            {
-                                //Set the device id to derive temporal PSK
-                                SetUuidForPinBasedOxm(&gDoxm->deviceID);
-
-                                /**
-                                 * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
-                                 * Credential should not be saved into SVR.
-                                 * For this reason, use a temporary get_psk_info callback to random PIN OxM.
-                                 */
-                                caRes = CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm);
-                                VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
-                                ehRet = OC_EH_OK;
-                            }
-                            else
-                            {
-                                OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
-                                ehRet = OC_EH_ERROR;
-                            }
-                        }
-                        else if(OC_ADAPTER_TCP == ehRequest->devAddr.adapter)
+                        if (!isDuplicatedMsg)
                         {
-                            if(OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
+                            char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
+                            if (OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
                             {
                                 //Set the device id to derive temporal PSK
                                 SetUuidForPinBasedOxm(&gDoxm->deviceID);
@@ -1224,7 +1403,6 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                                 OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
                                 ehRet = OC_EH_ERROR;
                             }
-
                         }
 #endif // __WITH_DTLS__ or __WITH_TLS__
                     }
@@ -1234,6 +1412,12 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         //Save the owner's UUID to derive owner credential
                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
 
+                        // In case of random-pin based OTM, close the PIN display if callback is registered.
+                        if (!isDuplicatedMsg)
+                        {
+                            ClosePinDisplay();
+                        }
+
                         //Update new state in persistent storage
                         if (UpdatePersistentStorage(gDoxm) == true)
                         {
@@ -1248,8 +1432,28 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
 #endif // __WITH_DTLS__ or __WITH_TLS__
                 }
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
-                else if (OIC_MANUFACTURER_CERTIFICATE ==  newDoxm->oxmSel)
+                else if (OIC_MANUFACTURER_CERTIFICATE ==  newDoxm->oxmSel || OIC_CON_MFG_CERT == newDoxm->oxmSel)
                 {
+                    //Get user confirmation
+                    if (false == newDoxm->owned &&
+                        false == isDuplicatedMsg &&
+                        memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)
+                    {
+                        gConfirmMsgId = ehRequest->messageID;
+                        gConfirmState = CONFIRM_STATE_WAIT;
+                        if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM))
+                        {
+                            ehRet = OC_EH_NOT_ACCEPTABLE;
+                            gConfirmState = CONFIRM_STATE_DENIED;
+                            goto exit;
+                        }
+                        else
+                        {
+                            ehRet = OC_EH_OK;
+                            gConfirmState = CONFIRM_STATE_ACCEPTED;
+                        }
+                    }
+
                     //Save the owner's UUID to derive owner credential
                     memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
                     gDoxm->oxmSel = newDoxm->oxmSel;
@@ -1267,6 +1471,11 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                     VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                     OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
+                    //Unset pre-selected ciphersuite, if any
+                    caRes = CASelectCipherSuite(0, ehRequest->devAddr.adapter);
+                    VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+                    OIC_LOG(DEBUG, TAG, "No ciphersuite preferred");
+
                     VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterPkixInfoHandler(GetManufacturerPkixInfo), ERROR);
                     VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterGetCredentialTypesHandler(InitManufacturerCipherSuiteList), ERROR);
                 }
@@ -1306,18 +1515,6 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                     ehRet = OC_EH_ERROR;
                     goto exit;
                 }
-                ownerRes = SetDpairingRownerId(&gDoxm->owner);
-                if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
-                {
-                    ehRet = OC_EH_ERROR;
-                    goto exit;
-                }
-                ownerRes = SetPconfRownerId(&gDoxm->owner);
-                if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
-                {
-                    ehRet = OC_EH_ERROR;
-                    goto exit;
-                }
 
                 gDoxm->owned = true;
                 memcpy(&gDoxm->rownerID, &gDoxm->owner, sizeof(OicUuid_t));
@@ -1342,11 +1539,15 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                     ehRet = OC_EH_ERROR;
                 }
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
-                if (OIC_MANUFACTURER_CERTIFICATE == gDoxm->oxmSel)
+                if (OIC_MANUFACTURER_CERTIFICATE == gDoxm->oxmSel ||
+                                            OIC_CON_MFG_CERT== gDoxm->oxmSel)
                 {
                     CAregisterPkixInfoHandler(GetPkixInfo);
                     CAregisterGetCredentialTypesHandler(InitCipherSuiteList);
                 }
+
+                InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+                                      &gDoxm->owner, OIC_OTM_DONE);
 #endif // __WITH_DTLS__ or __WITH_TLS__
             }
         }
@@ -1355,7 +1556,6 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
 exit:
     if(OC_EH_OK != ehRet)
     {
-
         /*
          * If some error is occured while ownership transfer,
          * ownership transfer related resource should be revert back to initial status.
@@ -1366,9 +1566,12 @@ exit:
             {
                 OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
 
-                if((OC_ADAPTER_IP == ehRequest->devAddr.adapter && previousMsgId != ehRequest->messageID)
-                   || OC_ADAPTER_TCP == ehRequest->devAddr.adapter)
+                if (!isDuplicatedMsg)
                 {
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+                    InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+                                          NULL, OIC_OTM_ERROR);
+#endif
                     RestoreDoxmToInitState();
                     RestorePstatToInitState();
                     OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
@@ -1380,20 +1583,92 @@ exit:
             OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
         }
     }
+
+    previousMsgId = ehRequest->messageID;
+
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+    CAEndpoint_t peer = {0};
+    OCDevAddr devAddr =  ehRequest->devAddr;
+
+    memcpy(&peer.addr, &devAddr.addr, sizeof(peer.addr));
+    peer.port = devAddr.port;
+    peer.adapter = (CATransportAdapter_t)devAddr.adapter;
+
+    if ((devAddr.flags & OC_FLAG_SECURE) && (false == CAIsExistSslPeer(&peer)))
+    {
+        OIC_LOG_V(WARNING, TAG, "Not Exist Peer");
+        ehRet = OC_EH_OK;
+    }
     else
     {
-        previousMsgId = ehRequest->messageID++;
+        //Send payload to request originator
+        ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+            OC_EH_OK : OC_EH_ERROR;
     }
-
+#else
     //Send payload to request originator
     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
-                   OC_EH_OK : OC_EH_ERROR;
+        OC_EH_OK : OC_EH_ERROR;
+#endif
 
     DeleteDoxmBinData(newDoxm);
 
     return ehRet;
 }
 
+#ifdef MULTIPLE_OWNER
+static OCEntityHandlerResult HandleDoxmDeleteRequest(const OCEntityHandlerRequest *ehRequest)
+{
+    OIC_LOG(DEBUG, TAG, "Processing DoxmDeleteRequest");
+
+    OCEntityHandlerResult ehRet = OC_EH_BAD_REQ;
+
+    if (NULL == ehRequest->query)
+    {
+        return ehRet;
+    }
+
+    OicParseQueryIter_t parseIter = { .attrPos=NULL };
+    OicUuid_t subject = {.id={0}};
+
+    //Parsing REST query to get the subject
+    ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
+    while (GetNextQuery(&parseIter))
+    {
+        if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBOWNERID_NAME,
+                parseIter.attrLen) == 0)
+        {
+            if (0 == strncmp((const char*)parseIter.valPos, WILDCARD_RESOURCE_URI,
+                             strlen(WILDCARD_RESOURCE_URI)))
+            {
+                if(OC_STACK_RESOURCE_DELETED == RemoveSubOwner(&WILDCARD_SUBJECT_ID))
+                {
+                    ehRet = OC_EH_RESOURCE_DELETED;
+                }
+            }
+            else
+            {
+                OCStackResult ret = ConvertStrToUuid((const char*)parseIter.valPos, &subject);
+                VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+                if(OC_STACK_RESOURCE_DELETED == RemoveSubOwner(&subject))
+                {
+                    ehRet = OC_EH_RESOURCE_DELETED;
+                }
+            }
+        }
+    }
+
+    //Send response to request originator
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+                   OC_EH_OK : OC_EH_ERROR;
+
+    return ehRet;
+exit:
+    return OC_EH_ERROR;
+}
+#endif //MULTIPLE_OWNER
+
 OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
                                         OCEntityHandlerRequest * ehRequest,
                                         void* callbackParam)
@@ -1420,6 +1695,12 @@ OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
                 ehRet = HandleDoxmPostRequest(ehRequest);
                 break;
 
+#ifdef MULTIPLE_OWNER
+            case OC_REST_DELETE:
+                ehRet = HandleDoxmDeleteRequest(ehRequest);
+                break;
+#endif //MULTIPLE_OWNER
+
             default:
                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
                                OC_EH_OK : OC_EH_ERROR;
@@ -1456,8 +1737,17 @@ OCStackResult CreateDoxmResource()
  */
 static OCStackResult CheckDeviceID()
 {
+    OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
+
     OCStackResult ret = OC_STACK_ERROR;
     bool validId = false;
+
+    if (!gDoxm)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: gDoxm is NULL", __func__);
+        return OC_STACK_INVALID_PARAM;
+    }
+
     for (uint8_t i = 0; i < UUID_LENGTH; i++)
     {
         if (gDoxm->deviceID.id[i] != 0)
@@ -1469,12 +1759,64 @@ static OCStackResult CheckDeviceID()
 
     if (!validId)
     {
-        if (OCGenerateUuid(gDoxm->deviceID.id) != RAND_UUID_OK)
+        char* strUuid = NULL;
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+        //If seed value is exist, generate UUID using seed with SHA256
+        if (0 != gUuidSeedSize)
+        {
+            uint8_t hashVal[MBEDTLS_MD_MAX_SIZE] = {0};
+            mbedtls_md_context_t sha_ctx;
+            int mbedret = 1;
+
+            OIC_LOG(DEBUG, TAG, "UUID will be generated using seed w/ SHA256");
+            OIC_LOG(DEBUG, TAG, "Seed value : ");
+            OIC_LOG_BUFFER(DEBUG, TAG, gUuidSeed, gUuidSeedSize);
+
+            mbedtls_md_init( &sha_ctx );
+            mbedret = mbedtls_md_setup( &sha_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 1 );
+            if (0 == mbedret)
+            {
+                mbedtls_md_starts( &sha_ctx );
+                mbedtls_md_update( &sha_ctx, gUuidSeed, gUuidSeedSize);
+                mbedtls_md_finish(&sha_ctx, (unsigned char*)hashVal);
+                memcpy(gDoxm->deviceID.id, hashVal, sizeof(gDoxm->deviceID.id));
+                ret = OC_STACK_OK;
+            }
+            else
+            {
+                OIC_LOG_V(ERROR, TAG,  "mbedtls_md_setup() returned -0x%04x\n", -mbedret);
+                ret = OC_STACK_ERROR;
+            }
+            mbedtls_md_free( &sha_ctx );
+        }
+        else
+        {
+            if (RAND_UUID_OK != OCGenerateUuid(gDoxm->deviceID.id))
+            {
+                OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
+                return OC_STACK_ERROR;
+            }
+            ret = OC_STACK_OK;
+        }
+#else
+        if (RAND_UUID_OK != OCGenerateUuid(gDoxm->deviceID.id))
         {
             OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
             return ret;
         }
         ret = OC_STACK_OK;
+#endif
+
+        if (OC_STACK_OK == ConvertUuidToStr(&gDoxm->deviceID, &strUuid))
+        {
+            OIC_LOG_V(DEBUG, TAG, "Generated device UUID is [%s]", strUuid);
+            OICFree(strUuid);
+        }
+        else
+        {
+            OIC_LOG(WARNING, TAG, "Failed to convert UUID to string");
+        }
+
 
         if (!UpdatePersistentStorage(gDoxm))
         {
@@ -1486,6 +1828,9 @@ static OCStackResult CheckDeviceID()
     {
         ret = OC_STACK_OK;
     }
+
+    OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
+
     return ret;
 }
 
@@ -1505,7 +1850,7 @@ const OicSecDoxm_t* GetDoxmResourceData()
     return gDoxm;
 }
 
-#if defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+#if defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
 /**
  * Internal API to prepare MOT
  */
@@ -1526,10 +1871,10 @@ static void PrepareMOT(const OicSecDoxm_t* doxm)
             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
             OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
-            caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, CA_ADAPTER_IP);
+            caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CA_ADAPTER_IP);
             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
 #ifdef __WITH_TLS__
-            caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, CA_ADAPTER_TCP);
+            caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CA_ADAPTER_TCP);
             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
 #endif
             OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
@@ -1551,12 +1896,15 @@ static void PrepareMOT(const OicSecDoxm_t* doxm)
 exit:
     OIC_LOG(WARNING, TAG, "Error in PrepareMOT");
 }
-#endif //defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+#endif //defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
 
 OCStackResult InitDoxmResource()
 {
     OCStackResult ret = OC_STACK_ERROR;
 
+    gConfirmState = CONFIRM_STATE_READY;
+    gConfirmMsgId = 0;
+
     //Read DOXM resource from PS
     uint8_t *data = NULL;
     size_t size = 0;
@@ -1582,10 +1930,13 @@ OCStackResult InitDoxmResource()
     }
 
     //In case of the server is shut down unintentionally, we should initialize the owner
-    if(false == gDoxm->owned)
+    if(gDoxm && (false == gDoxm->owned))
     {
         OicUuid_t emptyUuid = {.id={0}};
         memcpy(&gDoxm->owner, &emptyUuid, sizeof(OicUuid_t));
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+        InvokeOtmEventHandler(NULL, 0, NULL, OIC_OTM_READY);
+#endif
     }
 
     ret = CheckDeviceID();
@@ -1601,13 +1952,13 @@ OCStackResult InitDoxmResource()
     }
     OICFree(data);
 
-#if defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+#if defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
     //if MOT is enabled, MOT should be prepared.
     if(gDoxm && gDoxm->owned)
     {
         PrepareMOT(gDoxm);
     }
-#endif // defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+#endif // defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
 
     return ret;
 }
@@ -1651,26 +2002,55 @@ OCStackResult GetDoxmIsOwned(bool *isOwned)
     return OC_STACK_ERROR;
 }
 
-OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+OCStackResult SetDoxmDeviceIDSeed(const uint8_t* seed, size_t seedSize)
 {
-    bool isPT = false;
+    OIC_LOG_V(INFO, TAG, "In %s", __func__);
 
-    if(NULL == deviceID)
+    if (NULL == seed)
     {
         return OC_STACK_INVALID_PARAM;
     }
-    if(NULL == gDoxm)
+    if (MAX_UUID_SEED_SIZE < seedSize)
+    {
+        OIC_LOG_V(ERROR, TAG, "Seed size is too long (MAX size is %d bytes)", MAX_UUID_SEED_SIZE);
+        return OC_STACK_INVALID_PARAM;
+    }
+    if (MIN_UUID_SEED_SIZE > seedSize)
+    {
+        OIC_LOG_V(ERROR, TAG, "Seed size is too small (MIN size is %d bytes)", MIN_UUID_SEED_SIZE);
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    memset(gUuidSeed, 0x00, sizeof(gUuidSeed));
+    memcpy(gUuidSeed, seed, seedSize);
+    gUuidSeedSize = seedSize;
+
+    OIC_LOG_V(INFO, TAG, "Out %s", __func__);
+
+    return OC_STACK_OK;
+}
+
+#endif
+
+OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
+{
+    bool isOwnerUpdated = false;
+    bool isRownerUpdated = false;
+    if (NULL == deviceID)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    if (NULL == gDoxm)
     {
         OIC_LOG(ERROR, TAG, "Doxm resource is not initialized.");
         return OC_STACK_NO_RESOURCE;
     }
 
-    //Check the device's OTM state
-
 #ifdef __WITH_DTLS__
     //for normal device.
-    if(true == gDoxm->owned &&
-       memcmp(gDoxm->deviceID.id, gDoxm->owner.id, sizeof(gDoxm->owner.id)) != 0)
+    if (true == gDoxm->owned &&
+        memcmp(gDoxm->deviceID.id, gDoxm->owner.id, sizeof(gDoxm->owner.id)) != 0)
     {
         OIC_LOG(ERROR, TAG, "This device owned by owner's device.");
         OIC_LOG(ERROR, TAG, "Device UUID cannot be changed to guarantee the reliability of the connection.");
@@ -1679,27 +2059,40 @@ OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
 #endif //__WITH_DTLS
 
     //Save the previous UUID
-    OicUuid_t tempUuid;
-    memcpy(tempUuid.id, gDoxm->deviceID.id, sizeof(tempUuid.id));
+    OicUuid_t prevUuid;
+    memcpy(prevUuid.id, gDoxm->deviceID.id, sizeof(prevUuid.id));
 
-    //Change the UUID
+    //Change the device UUID
     memcpy(gDoxm->deviceID.id, deviceID->id, sizeof(deviceID->id));
-    if(isPT)
+
+    //Change the owner ID if necessary
+    if (memcmp(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id)) == 0)
     {
         memcpy(gDoxm->owner.id, deviceID->id, sizeof(deviceID->id));
+        isOwnerUpdated = true;
+    }
+    //Change the resource owner ID if necessary
+    if (memcmp(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id)) == 0)
+    {
         memcpy(gDoxm->rownerID.id, deviceID->id, sizeof(deviceID->id));
+        isRownerUpdated = true;
     }
+    // TODO: T.B.D Change resource owner for pstat, acl and cred
 
     //Update PS
-    if(!UpdatePersistentStorage(gDoxm))
+    if (!UpdatePersistentStorage(gDoxm))
     {
-        //revert UUID in case of update error
-        memcpy(gDoxm->deviceID.id, tempUuid.id, sizeof(tempUuid.id));
-        if(isPT)
+        //revert UUID in case of PSI error
+        memcpy(gDoxm->deviceID.id, prevUuid.id, sizeof(prevUuid.id));
+        if (isOwnerUpdated)
+        {
+            memcpy(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id));
+        }
+        if (isRownerUpdated)
         {
-            memcpy(gDoxm->owner.id, tempUuid.id, sizeof(tempUuid.id));
-            memcpy(gDoxm->rownerID.id, tempUuid.id, sizeof(tempUuid.id));
+            memcpy(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id));
         }
+        // TODO: T.B.D Revert resource owner for pstat, acl and cred
 
         OIC_LOG(ERROR, TAG, "Failed to update persistent storage");
         return OC_STACK_ERROR;
@@ -1737,7 +2130,7 @@ OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid)
     return retVal;
 }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
 /**
  * Compare the UUID to SubOwner.
  *
@@ -1749,17 +2142,22 @@ bool IsSubOwner(const OicUuid_t* uuid)
 {
     bool retVal = false;
 
-    if(NULL == uuid)
+    if (NULL == uuid)
     {
         return retVal;
     }
 
     if (gDoxm && gDoxm->subOwners)
     {
+        if (memcmp(gDoxm->owner.id, uuid->id, sizeof(gDoxm->owner.id)) == 0)
+        {
+            return false;
+        }
+
         OicSecSubOwner_t* subOwner = NULL;
         LL_FOREACH(gDoxm->subOwners, subOwner)
         {
-            if(memcmp(subOwner->uuid.id, uuid->id, sizeof(uuid->id)) == 0)
+            if (memcmp(subOwner->uuid.id, uuid->id, sizeof(uuid->id)) == 0)
             {
                 return true;
             }
@@ -1767,7 +2165,164 @@ bool IsSubOwner(const OicUuid_t* uuid)
     }
     return retVal;
 }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
+
+OCStackResult SetMOTStatus(bool enable)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+#ifdef MULTIPLE_OWNER
+    OCStackResult ret = OC_STACK_NO_MEMORY;
+    uint8_t *cborPayload = NULL;
+    size_t size = 0;
+    bool isDeallocateRequired = false;
+
+    VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+    
+    if (NULL == gDoxm->mom && !enable)
+    {
+        OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+        return OC_STACK_OK;
+    }
+
+    if (NULL == gDoxm->mom)
+    {
+        gDoxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+        VERIFY_NON_NULL(TAG, gDoxm->mom, ERROR);
+        isDeallocateRequired = true;
+    }
+
+    gDoxm->mom->mode = (enable ? OIC_MULTIPLE_OWNER_ENABLE : OIC_MULTIPLE_OWNER_DISABLE);
+    gDoxm->oxmSel = OIC_PRECONFIG_PIN;
+
+    ret = DoxmToCBORPayload(gDoxm, &cborPayload, &size, false);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+    ret = UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, cborPayload, size);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+    isDeallocateRequired = false;
+
+exit:
+    if (isDeallocateRequired)
+    {
+        OICFree(gDoxm->mom);
+    }
+    if (cborPayload)
+    {
+        OICFree(cborPayload);
+    }
+    OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, ret);
+    return ret;
+#else
+    OC_UNUSED(enable);
+    OIC_LOG(DEBUG, TAG, "Multiple Owner is not enabled.");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_ERROR;
+#endif //MULTIPLE_OWNER
+}
+
+OCStackResult RemoveSubOwner(const OicUuid_t* subOwner)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+#ifdef MULTIPLE_OWNER
+    OCStackResult ret = OC_STACK_ERROR;
+    bool isDeleted = false;
+
+    if (NULL == subOwner)
+    {
+        OIC_LOG(ERROR, TAG, "Invalid sub owner UUID.");
+        return OC_STACK_INVALID_PARAM;
+    }
+    if (NULL == gDoxm)
+    {
+        OIC_LOG(ERROR, TAG, "Doxm resource is NULL");
+        return OC_STACK_NO_RESOURCE;
+    }
+    if ( NULL == gDoxm->subOwners)
+    {
+        OIC_LOG(WARNING, TAG, "Sub Owner list is empty.");
+        return OC_STACK_ERROR;
+    }
+
+    OicSecSubOwner_t* curSubOwner = NULL;
+    OicSecSubOwner_t* tempSubOwner = NULL;
+    LL_FOREACH_SAFE(gDoxm->subOwners, curSubOwner, tempSubOwner)
+    {
+        if (memcmp(curSubOwner->uuid.id, subOwner->id, sizeof(subOwner->id)) == 0 ||
+            memcmp(WILDCARD_SUBJECT_ID.id, subOwner->id, sizeof(OicUuid_t)) == 0)
+        {
+            char* strUuid = NULL;
+            ret = ConvertUuidToStr(&curSubOwner->uuid, &strUuid);
+            if (OC_STACK_OK != ret)
+            {
+                OIC_LOG_V(ERROR, TAG, "ConvertUuidToStr error : %d", ret);
+                break;
+            }
+
+            OIC_LOG_V(INFO, TAG, "[%s] will be removed from sub owner list.", strUuid);
+            LL_DELETE(gDoxm->subOwners, curSubOwner);
+
+            //Remove the cred for sub owner
+            ret = RemoveCredential(&curSubOwner->uuid);
+            if (OC_STACK_RESOURCE_DELETED != ret)
+            {
+                OIC_LOG_V(WARNING, TAG, "RemoveCredential error for [%s] : %d", strUuid, ret);
+                break;
+            }
+
+            // TODO: Remove the ACL for sub owner (Currently ACL is not required for sub-owner)
+
+            OICFree(strUuid);
+
+            isDeleted = true;
+        }
+    }
+
+    if (isDeleted)
+    {
+        //Update persistent storage
+        if (UpdatePersistentStorage(gDoxm))
+        {
+            ret = OC_STACK_RESOURCE_DELETED;
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "UpdatePersistentStorage error");
+            ret = OC_STACK_ERROR;
+        }
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return ret;
+#else
+    OC_UNUSED(subOwner);
+    OIC_LOG(DEBUG, TAG, "Multiple Owner is not enabled.");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_ERROR;
+#endif //MULTIPLE_OWNER
+
+}
+
+OCStackResult SetNumberOfSubOwner(size_t numOfSubOwner)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+#ifdef MULTIPLE_OWNER
+    if (MAX_SUBOWNER_SIZE < numOfSubOwner || MIN_SUBOWNER_SIZE > numOfSubOwner)
+    {
+        OIC_LOG_V(ERROR, TAG, "Invalid number of sub owner : %d", numOfSubOwner);
+        return OC_STACK_INVALID_PARAM;
+    }
+    gMaxSubOwnerSize = numOfSubOwner;
+    OIC_LOG_V(DEBUG, TAG, "Number of SubOwner = %d", gMaxSubOwnerSize);
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_OK;
+#else
+    OC_UNUSED(numOfSubOwner);
+    OIC_LOG(DEBUG, TAG, "Multiple Owner is not enabled.");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_ERROR;
+#endif //MULTIPLE_OWNER
+}
 
 /**
  * Function to restore doxm resurce to initial status.
@@ -1775,6 +2330,10 @@ bool IsSubOwner(const OicUuid_t* uuid)
  */
 void RestoreDoxmToInitState()
 {
+
+    gConfirmState = CONFIRM_STATE_READY;
+    gConfirmMsgId = 0;
+
     if(gDoxm)
     {
         OIC_LOG(INFO, TAG, "DOXM resource will revert back to initial status.");
@@ -1790,3 +2349,38 @@ void RestoreDoxmToInitState()
         }
     }
 }
+
+OCStackResult SetDoxmSelfOwnership(const OicUuid_t* newROwner)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    uint8_t *cborPayload = NULL;
+    size_t size = 0;
+
+    if(NULL == gDoxm)
+    {
+        ret = OC_STACK_NO_RESOURCE;
+        return ret;
+    }
+
+    if( newROwner && (false == gDoxm->owned) )
+    {
+        gDoxm->owned = true;
+        memcpy(gDoxm->owner.id, newROwner->id, sizeof(newROwner->id));
+        memcpy(gDoxm->rownerID.id, newROwner->id, sizeof(newROwner->id));
+
+        ret = DoxmToCBORPayload(gDoxm, &cborPayload, &size, false);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        ret = UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, cborPayload, size);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        OICFree(cborPayload);
+    }
+
+    return ret;
+
+exit:
+    OICFree(cborPayload);
+    return ret;
+}
+