CONPRO-1467: Improve Reset
[platform/upstream/iotivity.git] / resource / csdk / security / src / doxmresource.c
index 02a8030..d8b4506 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"
+#include "octhread.h"
+#include "oic_time.h"
+#include "oic_string.h"
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#include "pkix_interface.h"
+#include "ca_adapter_net_ssl.h"
+#endif
 
-#define TAG  "SRM-DOXM"
+#define TAG  "OIC_SRM_DOXM"
 #define CHAR_ZERO ('0')
 
 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
@@ -62,8 +67,41 @@ 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 oc_mutex            g_mutexDoxm = NULL;
+static bool                g_isDoxmNull = false;
 static OCResourceHandle    gDoxmHandle = NULL;
+static oc_mutex            g_mutexWait;
+static oc_thread           g_waitConfirmThreadId;
+oc_cond                    g_condWait;
+static InformOxmSelectedCallback_t g_InformOxmSelectedCallback = NULL;
+static bool                g_isConfirmResult;
 
 static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS;
 static OicSecDoxm_t gDefaultDoxm =
@@ -78,13 +116,18 @@ 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;
+
+static uint8_t gEmptyUuid[UUID_LENGTH] = {0};
+
 /**
  * This method is internal method.
  * the param roParsed is optionally used to know whether cborPayload has
@@ -107,7 +150,7 @@ void DeleteDoxmBinData(OicSecDoxm_t* doxm)
         //clean oxm
         OICFree(doxm->oxm);
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
         //clean mom
         OICFree(doxm->mom);
 
@@ -122,11 +165,17 @@ void DeleteDoxmBinData(OicSecDoxm_t* doxm)
                 OICFree(subowner);
             }
         }
-#endif //_ENABLE_MULTIPLE_OWNER_
+#endif //MULTIPLE_OWNER
 
         //Clean doxm itself
         OICFree(doxm);
     }
+
+    if(g_mutexDoxm)
+    {
+        oc_mutex_free(g_mutexDoxm);
+        g_mutexDoxm = NULL;
+    }
 }
 
 OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, size_t *size,
@@ -236,7 +285,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)
     {
@@ -277,7 +326,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,
@@ -301,13 +350,6 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz
     OICFree(strUuid);
     strUuid = NULL;
 
-    //x.org.iotivity.dpc -- not Mandatory(vendor-specific), but this type is boolean, so instance always has a value.
-    cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DPC_NAME,
-        strlen(OIC_JSON_DPC_NAME));
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Tag.");
-    cborEncoderResult = cbor_encode_boolean(&doxmMap, doxm->dpc);
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Value.");
-
     //RT -- Mandatory
     CborEncoder rtArray;
     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_RT_NAME,
@@ -345,7 +387,7 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz
 
     if (CborNoError == cborEncoderResult)
     {
-        *size = encoder.ptr - outPayload;
+        *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
         *payload = outPayload;
         ret = OC_STACK_OK;
     }
@@ -355,8 +397,9 @@ 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 += encoder.ptr - encoder.end;
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
         OIC_LOG_V(DEBUG, TAG, "Doxm reallocation size : %zd.", cborLen);
         cborEncoderResult = CborNoError;
         ret = DoxmToCBORPayload(doxm, payload, &cborLen, rwOnly);
@@ -522,18 +565,6 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
         doxm->owned = gDoxm->owned;
     }
 
-    cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DPC_NAME, &doxmMap);
-    if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
-    {
-        cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->dpc);
-        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding DPC Value.")
-    }
-    else // PUT/POST JSON may not have dpc so set it to the gDomx->dpc
-    {
-        VERIFY_NON_NULL(TAG, gDoxm, ERROR);
-        doxm->dpc = gDoxm->dpc;
-    }
-
     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVICE_ID_NAME, &doxmMap);
     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
     {
@@ -543,11 +574,6 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
         OICFree(strUuid);
         strUuid  = NULL;
-
-        if (roParsed)
-        {
-            *roParsed = true;
-        }
     }
     else
     {
@@ -571,7 +597,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))
     {
@@ -645,7 +671,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))
@@ -732,10 +758,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};
 
@@ -758,10 +783,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)
             {
@@ -779,7 +803,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)
         {
@@ -804,14 +828,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)
@@ -873,30 +891,16 @@ static void updateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst)
         //update rowner
         memcpy(&(dst->rownerID), &(src->rownerID), sizeof(OicUuid_t));
 
+        //update deviceuuid
+        memcpy(&(dst->deviceID), &(src->deviceID), sizeof(OicUuid_t));
+
         //Update owned status
         if(dst->owned != src->owned)
         {
             dst->owned = src->owned;
         }
 
-        //update oxms
-        if(0 < src->oxmLen)
-        {
-            OicSecOxm_t* tempOxm = (OicSecOxm_t*)OICMalloc(sizeof(OicSecOxm_t) * src->oxmLen);
-            if(NULL != tempOxm)
-            {
-                for(size_t i = 0; i < src->oxmLen; i++)
-                {
-                    tempOxm[i] = src->oxm[i];
-                }
-                OICFree(dst->oxm);
-
-                dst->oxm = tempOxm;
-                dst->oxmLen = src->oxmLen;
-            }
-        }
-
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
         if(src->mom)
         {
             OIC_LOG(DEBUG, TAG, "dectected 'mom' property");
@@ -909,36 +913,127 @@ 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=%zd", 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)
         {
-            OicSecSubOwner_t* subOwnerInst = (OicSecSubOwner_t*)OICMalloc(sizeof(OicSecSubOwner_t));
-            if(subOwnerInst)
+            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)
+            {
+                if(0 == memcmp(subOwnerInst->uuid.id,
+                               authenticatedSubOwnerInfo->identity.id,
+                               authenticatedSubOwnerInfo->identity.id_length))
+                {
+                    break;
+                }
+            }
+
+            if (NULL == 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))
+                subOwnerInst = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+                if (subOwnerInst)
                 {
-                    OIC_LOG(ERROR, TAG, "Failed to register SubOwner UUID into Doxm");
+                    char* strUuid = NULL;
+                    if (OC_STACK_OK != ConvertUuidToStr(&subOwnerInst->uuid, &strUuid))
+                    {
+                        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=%zd)", 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);
                 }
             }
         }
@@ -949,17 +1044,202 @@ 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 //MULTIPLE_OWNER
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+/**
+ * Function to validate oxmsel with oxms.
+ *
+ * @param[in] supportedMethods   Array of supported methods
+ * @param[in] numberOfMethods   number of supported methods
+ * @param[out]  selectedMethod         Selected methods
+ * @return  TRUE on success
+ */
+static bool ValidateOxmsel(const OicSecOxm_t *supportedMethods,
+        size_t numberOfMethods, OicSecOxm_t *selectedMethod)
+{
+    bool isValidOxmsel = false;
+
+    OIC_LOG(DEBUG, TAG, "IN ValidateOxmsel");
+    if (numberOfMethods == 0 || !supportedMethods)
+    {
+        OIC_LOG(WARNING, TAG, "Could not find a supported OxM.");
+        return isValidOxmsel;
+    }
+
+    for (size_t i = 0; i < numberOfMethods; i++)
+    {
+            if (*selectedMethod  == supportedMethods[i])
+            {
+                isValidOxmsel = true;
+                break;
+            }
+    }
+    if (!isValidOxmsel)
+    {
+        OIC_LOG(ERROR, TAG, "Not allowed Oxmsel.");
+        return isValidOxmsel;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT ValidateOxmsel");
+
+    return isValidOxmsel;
+}
+
+void SetInformOxmSelCB(InformOxmSelectedCallback_t informOxmSelCB)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    g_InformOxmSelectedCallback = informOxmSelCB;
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+}
+
+void UnsetInformOxmSelCB()
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    g_InformOxmSelectedCallback = NULL;
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+}
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest);
+
+static void DestroyEntityHandlerRequest(OCEntityHandlerRequest * ehRequest)
+{
+    if (ehRequest == NULL) {
+        OIC_LOG(WARNING, TAG, "ehRequest is NULL");
+        return;
+    }
+
+    OICFree(ehRequest->query);
+
+    if (ehRequest->payload) {
+        OICFree(((OCSecurityPayload *)ehRequest->payload)->securityData);
+        OICFree(ehRequest->payload);
+    }
+
+    OICFree(ehRequest);
+}
+
+void * WaitConfirm(OCEntityHandlerRequest * ehRequest)
+{
+    bool confirmResult = false, confirmState = false;
+
+    oc_mutex_lock(g_mutexWait);
+    oc_cond_wait(g_condWait, g_mutexWait);
+    oc_cond_free(g_condWait);
+    g_condWait = NULL;
+
+    oc_mutex_unlock(g_mutexWait);
+    oc_mutex_free(g_mutexWait);
+    g_mutexWait = NULL;
+
+    g_isConfirmResult = true;
+    GetAsyncVerifyUserResult(&confirmResult, &confirmState);
+    if (confirmResult == true)
+    {
+        gConfirmState = CONFIRM_STATE_ACCEPTED;
+        HandleDoxmPostRequest(ehRequest);
+        g_isConfirmResult = false;
+    }
+    else
+    {
+        gConfirmState = CONFIRM_STATE_DENIED;
+        HandleDoxmPostRequest(ehRequest);
+        g_isConfirmResult = false;
+    }
+
+    DestroyEntityHandlerRequest(ehRequest);
+
+    return NULL;
+}
+
+static OCEntityHandlerRequest *CopyRequest(OCEntityHandlerRequest *entityHandlerRequest)
+{
+    OIC_LOG(INFO, TAG, "Copying received request for slow response");
+
+    if (!entityHandlerRequest)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: entityHandlerRequest is NULL", __func__);
+        return NULL;
+    }
+
+    OCEntityHandlerRequest *copyOfRequest =
+            (OCEntityHandlerRequest *)OICCalloc(1, sizeof(OCEntityHandlerRequest));
+    if(!copyOfRequest)
+    {
+        OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+        return NULL;
+    }
+
+    memcpy(copyOfRequest, entityHandlerRequest, sizeof(OCEntityHandlerRequest));
+
+    if (entityHandlerRequest->query)
+    {
+        copyOfRequest->query = OICStrdup(entityHandlerRequest->query);
+        if(!copyOfRequest->query)
+        {
+            OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+            OICFree(copyOfRequest);
+            return NULL;
+        }
+    }
+
+    if (entityHandlerRequest->payload)
+    {
+        copyOfRequest->payload =
+                (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload));
+        if(!copyOfRequest->payload)
+        {
+            OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+            OICFree(copyOfRequest->query);
+            OICFree(copyOfRequest);
+            return NULL;
+        }
+
+        if (((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize)
+        {
+            ((OCSecurityPayload *)copyOfRequest->payload)->securityData =
+                    (uint8_t *)OICCalloc(1, ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+            if(!((OCSecurityPayload *)copyOfRequest->payload)->securityData)
+            {
+                OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+                OICFree(copyOfRequest->payload);
+                OICFree(copyOfRequest->query);
+                OICFree(copyOfRequest);
+                return NULL;
+            }
+
+            memcpy(((OCSecurityPayload *)copyOfRequest->payload)->securityData,
+                  ((OCSecurityPayload *)entityHandlerRequest->payload)->securityData,
+                  ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+
+            ((OCSecurityPayload *)(copyOfRequest->payload))->payloadSize =
+                    ((OCSecurityPayload *)(entityHandlerRequest->payload))->payloadSize;
+        }
+
+        copyOfRequest->payload->type = entityHandlerRequest->payload->type;
+        copyOfRequest->messageID = entityHandlerRequest->messageID;
+    }
+
+    // Ignore vendor specific header options for example
+    copyOfRequest->numRcvdVendorSpecificHeaderOptions = 0;
+    copyOfRequest->rcvdVendorSpecificHeaderOptions = NULL;
+
+    OIC_LOG(INFO, TAG, "Copied client request");
+
+    return copyOfRequest;
 }
-#endif //_ENABLE_MULTIPLE_OWNER_
 #endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 
-static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest * ehRequest)
+static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest)
 {
     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing POST request");
     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
@@ -975,6 +1255,34 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
         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 && g_isConfirmResult == false)
+            {
+                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)
             {
@@ -983,14 +1291,29 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                 goto exit;
             }
 
+            VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+
             // in owned state
             if (true == gDoxm->owned)
             {
+                if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
+                {
+                    OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
+                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                    goto exit;
+                }
+
+                if(0 != memcmp(&gDoxm->owner.id, &newDoxm->owner.id, sizeof(gDoxm->owner.id)))
+                {
+                    OIC_LOG(ERROR, TAG, "Not acceptable request for owned property");
+                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                }
+
                 //Update gDoxm based on newDoxm
                 updateWriteableProperty(newDoxm, gDoxm);
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
                 //handle mom
                 if(gDoxm->mom)
                 {
@@ -1003,7 +1326,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                             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");
 
@@ -1051,7 +1374,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                         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
@@ -1070,7 +1393,36 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
             // in unowned state
             if ((false == gDoxm->owned) && (false == newDoxm->owned))
             {
-                if (OIC_JUST_WORKS == newDoxm->oxmSel)
+                if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
+                {
+                    OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
+                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                    goto exit;
+                }
+                if (g_InformOxmSelectedCallback)
+                {
+                    g_InformOxmSelectedCallback(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);
+                }
+                else
+                {
+                    OIC_LOG_V(INFO, TAG, "%s: request owner not empty",__func__);
+                    char* strUuid = NULL;
+                    if (OC_STACK_OK == ConvertUuidToStr(&newDoxm->owner, &strUuid))
+                    {
+                        OIC_LOG_V(INFO, TAG, "%s: request owner: %s",__func__, strUuid);
+                        OICFree(strUuid);
+                    }
+                }
+#endif
+
+                if (OIC_JUST_WORKS == newDoxm->oxmSel || OIC_MV_JUST_WORKS == newDoxm->oxmSel)
                 {
                     /*
                      * If current state of the device is un-owned, enable
@@ -1079,6 +1431,18 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                      */
                     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;
@@ -1100,6 +1464,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                         {
                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
                             ehRet = OC_EH_ERROR;
+                            goto exit;
                         }
 
                         /*
@@ -1111,6 +1476,59 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                         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__
                     }
                 }
@@ -1142,15 +1560,14 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                         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_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 (!isDuplicatedMsg)
                         {
-                            if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
+                            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);
@@ -1170,36 +1587,19 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                                 ehRet = OC_EH_ERROR;
                             }
                         }
-                        else if(previousMsgId != ehRequest->messageID)
+#endif // __WITH_DTLS__ or __WITH_TLS__
+                    }
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+                    else
+                    {
+                        //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)
                         {
-                            if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
-                            {
-                                //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;
-                            }
-
-                        }
-#endif // __WITH_DTLS__ or __WITH_TLS__
-                    }
-#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
-                    else
-                    {
-                        //Save the owner's UUID to derive owner credential
-                        memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+                            ClosePinDisplay();
+                        }
 
                         //Update new state in persistent storage
                         if (UpdatePersistentStorage(gDoxm) == true)
@@ -1214,6 +1614,78 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                     }
 #endif // __WITH_DTLS__ or __WITH_TLS__
                 }
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+                else if (OIC_MANUFACTURER_CERTIFICATE ==  newDoxm->oxmSel || OIC_CON_MFG_CERT == newDoxm->oxmSel)
+                {
+                    if (CONFIRM_STATE_ACCEPTED != gConfirmState && CONFIRM_STATE_DENIED != gConfirmState)
+                    {
+                        //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 != VerifyUserConfirm())
+                            {
+                                if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM))
+                                {
+                                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                                    gConfirmState = CONFIRM_STATE_DENIED;
+                                    goto exit;
+                                }
+                            }
+                            else
+                            {
+                                OCEntityHandlerRequest * ehRequestCopy = CopyRequest(ehRequest);
+                                VERIFY_NON_NULL(TAG, ehRequestCopy, ERROR);
+
+                                g_condWait = oc_cond_new();
+                                g_mutexWait = oc_mutex_new();
+                                if (oc_thread_new (&g_waitConfirmThreadId, WaitConfirm, ehRequestCopy))
+                                {
+                                    oc_thread_detach(g_waitConfirmThreadId);
+                                }
+
+                                previousMsgId = ehRequest->messageID;
+
+                                return OC_EH_SLOW;
+                            }
+                        }
+                    }
+                    else if (CONFIRM_STATE_DENIED == gConfirmState)
+                    {
+                        ehRet = OC_EH_NOT_ACCEPTABLE;
+                        goto exit;
+                    }
+
+                    //Save the owner's UUID to derive owner credential
+                    memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+                    gDoxm->oxmSel = newDoxm->oxmSel;
+                    //Update new state in persistent storage
+                    if (UpdatePersistentStorage(gDoxm))
+                    {
+                        ehRet = OC_EH_OK;
+                    }
+                    else
+                    {
+                        OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
+                        ehRet = OC_EH_ERROR;
+                    }
+                    CAResult_t caRes = CAEnableAnonECDHCipherSuite(false);
+                    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);
+                }
+#endif // __WITH_DTLS__ or __WITH_TLS__
             }
 
             /*
@@ -1249,18 +1721,6 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                     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));
@@ -1284,6 +1744,17 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                     OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
                     ehRet = OC_EH_ERROR;
                 }
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+                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__
             }
         }
     }
@@ -1291,19 +1762,25 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
 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.
         */
         if(gDoxm)
         {
-            if(!gDoxm->owned && previousMsgId != ehRequest->messageID)
+            if(!gDoxm->owned)
             {
-                OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request,"\
-                                    "DOXM will be reverted.");
-                RestoreDoxmToInitState();
-                RestorePstatToInitState();
+                OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
+
+                if (!isDuplicatedMsg)
+                {
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+                    InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+                                          NULL, OIC_OTM_ERROR);
+#endif
+                    ResetSecureResourceInPS();
+                    OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
+                }
             }
         }
         else
@@ -1311,20 +1788,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)
@@ -1337,6 +1886,14 @@ OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
         return ehRet;
     }
 
+    oc_mutex_lock(g_mutexDoxm);
+
+    if(g_isDoxmNull)
+    {
+        oc_mutex_unlock(g_mutexDoxm);
+        return OC_EH_SERVICE_UNAVAILABLE;
+    }
+
     if (flag & OC_REQUEST_FLAG)
     {
         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
@@ -1351,11 +1908,19 @@ 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;
                 break;
         }
+
+        oc_mutex_unlock(g_mutexDoxm);
     }
 
     return ehRet;
@@ -1387,8 +1952,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)
@@ -1400,12 +1974,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))
         {
@@ -1417,6 +2043,9 @@ static OCStackResult CheckDeviceID()
     {
         ret = OC_STACK_OK;
     }
+
+    OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
+
     return ret;
 }
 
@@ -1436,7 +2065,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
  */
@@ -1457,10 +2086,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");
@@ -1482,12 +2111,24 @@ 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;
 
+    if (!g_mutexDoxm)
+    {
+        g_mutexDoxm = oc_mutex_new();
+            if(!g_mutexDoxm)
+            {
+                return OC_STACK_ERROR;
+            }
+    }
+
+    gConfirmState = CONFIRM_STATE_READY;
+    gConfirmMsgId = 0;
+
     //Read DOXM resource from PS
     uint8_t *data = NULL;
     size_t size = 0;
@@ -1512,11 +2153,18 @@ OCStackResult InitDoxmResource()
         gDoxm = GetDoxmDefault();
     }
 
+     oc_mutex_lock(g_mutexDoxm);
+     g_isDoxmNull = false;
+     oc_mutex_unlock(g_mutexDoxm);
+
     //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();
@@ -1532,32 +2180,36 @@ 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;
 }
 
 OCStackResult DeInitDoxmResource()
 {
+    oc_mutex_lock(g_mutexDoxm);
     OCStackResult ret = OCDeleteResource(gDoxmHandle);
     if (gDoxm  != &gDefaultDoxm)
     {
         DeleteDoxmBinData(gDoxm);
     }
     gDoxm = NULL;
+    g_isDoxmNull = true;
 
     if (OC_STACK_OK == ret)
     {
+        oc_mutex_unlock(g_mutexDoxm);
         return OC_STACK_OK;
     }
     else
     {
+        oc_mutex_unlock(g_mutexDoxm);
         return OC_STACK_ERROR;
     }
 }
@@ -1582,26 +2234,56 @@ 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(gEmptyUuid, gDoxm->owner.id, sizeof(gDoxm->owner.id)) != 0
+            && 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.");
@@ -1610,27 +2292,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, tempUuid.id, sizeof(tempUuid.id));
-            memcpy(gDoxm->rownerID.id, tempUuid.id, sizeof(tempUuid.id));
+            memcpy(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id));
         }
+        if (isRownerUpdated)
+        {
+            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;
@@ -1668,7 +2363,7 @@ OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid)
     return retVal;
 }
 
-#ifdef _ENABLE_MULTIPLE_OWNER_
+#ifdef MULTIPLE_OWNER
 /**
  * Compare the UUID to SubOwner.
  *
@@ -1680,17 +2375,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;
             }
@@ -1698,7 +2398,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 : %zd", numOfSubOwner);
+        return OC_STACK_INVALID_PARAM;
+    }
+    gMaxSubOwnerSize = numOfSubOwner;
+    OIC_LOG_V(DEBUG, TAG, "Number of SubOwner = %zd", 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.
@@ -1706,6 +2563,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.");
@@ -1721,3 +2582,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;
+}
+