replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / multipleownershiptransfermanager.c
index 6a84d27..fb7104c 100644 (file)
 #include "cacommon.h"
 #include "cainterface.h"
 #include "base64.h"
+#if defined (__TIZENRT__)
+#include <apps/netutils/cJSON.h>
+#else
 #include "cJSON.h"
-#include "global.h"
+#endif
 
 #include "srmresourcestrings.h"
 #include "doxmresource.h"
@@ -78,7 +81,7 @@
 static OCStackApplicationResult MOTUpdateSecurityResourceCB(void *ctx, OCDoHandle UNUSED,
                                                 OCClientResponse *clientResponse)
 {
-    OIC_LOG_V(INFO, TAG, "Inside MOTUpdateMomCB.");
+    OIC_LOG_V(INFO, TAG, "In %s", __func__);
     (void)UNUSED;
     OTMContext_t *motCtx = (OTMContext_t*)ctx;
     VERIFY_NON_NULL(TAG, motCtx, ERROR);
@@ -117,10 +120,68 @@ exit:
         OICFree(motCtx->ctxResultArray);
         OICFree(motCtx);
     }
+    OIC_LOG_V(INFO, TAG, "Out %s", __func__);
     return OC_STACK_DELETE_TRANSACTION;
 }
 
 /**
+ * Callback handler of security resource's DELETE request.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult MOTDeleteSecurityResourceCB(void *ctx, OCDoHandle UNUSED,
+                                                OCClientResponse *clientResponse)
+{
+    OIC_LOG_V(INFO, TAG, "In %s", __func__);
+    (void)UNUSED;
+    OTMContext_t *motCtx = (OTMContext_t*)ctx;
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+    VERIFY_NON_NULL(TAG, motCtx->ctxResultCallback, ERROR);
+    VERIFY_NON_NULL(TAG, motCtx->ctxResultArray, ERROR);
+
+    if(clientResponse)
+    {
+        memcpy(motCtx->ctxResultArray[0].deviceId.id,
+               motCtx->selectedDeviceInfo->doxm->deviceID.id,
+               sizeof(OicUuid_t));
+        motCtx->ctxResultArray[0].res = clientResponse->result;
+
+        if(OC_STACK_RESOURCE_DELETED == clientResponse->result)
+        {
+            motCtx->ctxHasError = false;
+        }
+        else
+        {
+            motCtx->ctxHasError = true;
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "SRPGetACLResourceCB received Null clientResponse");
+        motCtx->ctxResultArray[0].res = OC_STACK_ERROR;
+        motCtx->ctxHasError = true;
+    }
+
+    motCtx->ctxResultCallback(motCtx->userCtx, motCtx->ctxResultArraySize,
+                              motCtx->ctxResultArray, motCtx->ctxHasError);
+
+exit:
+    if(motCtx)
+    {
+        OICFree(motCtx->ctxResultArray);
+        OICFree(motCtx);
+    }
+    OIC_LOG_V(INFO, TAG, "Out %s", __func__);
+
+    return OC_STACK_DELETE_TRANSACTION;
+
+}
+
+/**
  * Internal API to send POST doxm request
  */
 static OCStackResult MOTSendPostDoxm(void *ctx,
@@ -133,7 +194,7 @@ static OCStackResult MOTSendPostDoxm(void *ctx,
     OTMContext_t *motCtx = NULL;
     bool freeFlag = true;
 
-    OIC_LOG(DEBUG, TAG, "IN MOTSendPostDoxm");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     //Generate the security payload using updated doxm
     secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
@@ -178,8 +239,6 @@ static OCStackResult MOTSendPostDoxm(void *ctx,
 
     freeFlag = false;
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTSendPostDoxm");
-
 exit:
     //If POST request successfully sent, motCtx will be cleaned from response handler.
     if(freeFlag && motCtx)
@@ -187,7 +246,7 @@ exit:
         OICFree(motCtx->ctxResultArray);
         OICFree(motCtx);
     }
-
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
     return postMomRes;
 }
 
@@ -208,7 +267,7 @@ OCStackResult MOTChangeMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
     uint8_t* doxmPayload = NULL;
     size_t doxmPayloadLen = 0;
 
-    OIC_LOG(DEBUG, TAG, "IN MOTChangeMode");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     VERIFY_SUCCESS(TAG, (OIC_NUMBER_OF_MOM_TYPE > momType), ERROR);
     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
@@ -235,11 +294,10 @@ OCStackResult MOTChangeMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTChangeMode");
-
 exit:
     OICFree(doxmPayload);
     DeleteDoxmBinData(doxm);
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
     return postMomRes;
 }
 
@@ -260,7 +318,7 @@ OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
     uint8_t* doxmPayload = NULL;
     size_t doxmPayloadLen = 0;
 
-    OIC_LOG(DEBUG, TAG, "IN MOTAddMOTMethod");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > newOxm || OIC_PRECONFIG_PIN == newOxm), ERROR);
     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
@@ -298,10 +356,9 @@ OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
     postOxmRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, targetDeviceInfo->doxm);
     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postOxmRes), ERROR);
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTAddMOTMethod");
-
 exit:
     OICFree(doxmPayload);
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
     return postOxmRes;
 }
 
@@ -322,7 +379,7 @@ OCStackResult MOTSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDevice
     uint8_t* doxmPayload = NULL;
     size_t doxmPayloadLen = 0;
 
-    OIC_LOG(DEBUG, TAG, "IN MOTSelectOTMethod");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
     postMomRes = OC_STACK_INVALID_PARAM;
@@ -353,11 +410,10 @@ OCStackResult MOTSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDevice
     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTSelectOTMethod");
-
 exit:
     OICFree(doxmPayload);
     DeleteDoxmBinData(doxm);
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
     return postMomRes;
 }
 
@@ -380,7 +436,7 @@ OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *target
     OTMContext_t *motCtx = NULL;
     OicSecCred_t* pinCred = NULL;
 
-    OIC_LOG(DEBUG, TAG, "IN MOTProvisionPreconfigPIN");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
     postCredRes = OC_STACK_INVALID_PARAM;
@@ -447,7 +503,7 @@ OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *target
 
     freeFlag = false;
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTProvisionPreconfigPIN");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 
     return postCredRes;
 
@@ -463,6 +519,7 @@ exit:
         OICFree(pinCred->privateData.data);
         OICFree(pinCred);
     }
+    OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, postCredRes);
     return postCredRes;
 }
 
@@ -497,7 +554,7 @@ static bool IsComplete(OTMContext_t* otmCtx)
  */
 static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
 {
-    OIC_LOG_V(DEBUG, TAG, "IN SetMOTResult : %d ", res);
+    OIC_LOG_V(DEBUG, TAG, "IN %s : %d ", __func__, res);
     VERIFY_NON_NULL(TAG, motCtx, ERROR);
 
     if(motCtx->selectedDeviceInfo)
@@ -556,6 +613,7 @@ static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
 
             OICFree(motCtx->ctxResultArray);
             OICFree(motCtx);
+            motCtx = NULL;
         }
         else
         {
@@ -568,7 +626,7 @@ static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
     }
 
 exit:
-    OIC_LOG(DEBUG, TAG, "OUT SetMOTResult");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 }
 
 /**
@@ -588,7 +646,7 @@ OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
     OicSecCred_t* pinCred = NULL;
     bool freeFlag = true;
 
-    OIC_LOG(DEBUG, TAG, "IN MOTAddPreconfigPIN");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
@@ -620,7 +678,7 @@ OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
     addCredRes = AddCredential(pinCred);
     VERIFY_SUCCESS(TAG, (OC_STACK_OK == addCredRes), ERROR);
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTAddPreconfigPIN");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 
     return addCredRes;
 
@@ -630,6 +688,7 @@ exit:
         OICFree(pinCred->privateData.data);
         OICFree(pinCred);
     }
+    OIC_LOG_V(DEBUG, TAG, "In %s : %d", __func__, addCredRes);
     return addCredRes;
 }
 
@@ -641,7 +700,7 @@ exit:
  */
 static OCStackResult SaveSubOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
 {
-    OIC_LOG(DEBUG, TAG, "IN SaveSubOwnerPSK");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     OCStackResult res = OC_STACK_ERROR;
 
@@ -709,7 +768,7 @@ static OCStackResult SaveSubOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
         OIC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT SaveSubOwnerPSK");
+    OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, res);
 exit:
     return res;
 }
@@ -730,7 +789,8 @@ static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle
     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
     VERIFY_NON_NULL(TAG, ctx, WARNING);
 
-    OIC_LOG(DEBUG, TAG, "IN SubOwnerCredentialHandler");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
     (void)UNUSED;
     OTMContext_t* motCtx = (OTMContext_t*)ctx;
 
@@ -738,27 +798,39 @@ static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle
     {
         if(motCtx && motCtx->selectedDeviceInfo)
         {
-            //Close the temporal secure session to verify the owner credential
-            CAEndpoint_t* endpoint = (CAEndpoint_t *)&motCtx->selectedDeviceInfo->endpoint;
-            endpoint->port = motCtx->selectedDeviceInfo->securePort;
-            CAResult_t caResult = CAcloseSslSession(endpoint);
-            if(CA_STATUS_OK != caResult)
+            //Delete previous credential such as preconfigured-pin
+            RemoveCredential(&(motCtx->selectedDeviceInfo->doxm->deviceID));
+            OCStackResult res = SaveSubOwnerPSK(motCtx->selectedDeviceInfo);
+            if(OC_STACK_OK == res)
             {
-                OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
-                SetMOTResult(motCtx, OC_STACK_ERROR);
-                return OC_STACK_DELETE_TRANSACTION;
-            }
+                //Close the temporal secure session to verify the owner credential
+                CAEndpoint_t* endpoint = (CAEndpoint_t *)&motCtx->selectedDeviceInfo->endpoint;
+                endpoint->port = motCtx->selectedDeviceInfo->securePort;
+                CAResult_t caResult = CAcloseSslSession(endpoint);
+                if(CA_STATUS_OK != caResult)
+                {
+                    OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
+                    SetMOTResult(motCtx, OC_STACK_ERROR);
+                    return OC_STACK_DELETE_TRANSACTION;
+                }
+
+                // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
+                caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
+                if(CA_STATUS_OK != caResult)
+                {
+                    OIC_LOG(ERROR, TAG, "Failed to select TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256");
+                    SetMOTResult(motCtx, OC_STACK_ERROR);
+                    return OC_STACK_DELETE_TRANSACTION;
+                }
 
-            // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
-            caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
-            if(CA_STATUS_OK != caResult)
+                SetMOTResult(motCtx, OC_STACK_OK);
+            }
+            else
             {
-                OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
-                SetMOTResult(motCtx, OC_STACK_ERROR);
+                OIC_LOG(ERROR, TAG, "Failed to save the SubOwner PSK.");
+                SetMOTResult(motCtx, res);
                 return OC_STACK_DELETE_TRANSACTION;
             }
-
-            SetMOTResult(motCtx, OC_STACK_OK);
         }
     }
     else
@@ -768,7 +840,7 @@ static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle
         SetMOTResult(motCtx, clientResponse->result);
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT SubOwnerCredentialHandler");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 
 exit:
     return  OC_STACK_DELETE_TRANSACTION;
@@ -777,7 +849,7 @@ exit:
 
 static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
 {
-    OIC_LOG(DEBUG, TAG, "IN PostSubOwnerCredential");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     if(!motCtx || !motCtx->selectedDeviceInfo)
     {
@@ -806,19 +878,18 @@ static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
 
     //Generate sub-owner credential for new device
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
-    const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID));
-    if(!ownerCredential)
-    {
-        OIC_LOG(ERROR, TAG, "Can not find SubOwnerPSK.");
-        return OC_STACK_NO_RESOURCE;
-    }
 
+    /**
+     * Because of the deadlock issue, we can not get a server's session information at this time.
+     * So use the dumpy owner credential instance to send POST credential request.
+     */
     OicUuid_t ownerId = {.id={0}};
     if(OC_STACK_OK == GetDoxmDeviceID(&ownerId))
     {
         OicSecCred_t newCredential;
-        memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t));
+        memset(&newCredential, 0x0, sizeof(OicSecCred_t));
         newCredential.next = NULL;
+        newCredential.credType = SYMMETRIC_PAIR_WISE_KEY;
 
         //Set subject ID as SubOwner's ID
         memcpy(&(newCredential.subject), &ownerId, sizeof(OicUuid_t));
@@ -837,10 +908,12 @@ static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
         //Fill private data as empty string
         newCredential.privateData.data = "";
         newCredential.privateData.len = 0;
-        newCredential.privateData.encoding = ownerCredential->privateData.encoding;
-#ifdef __WITH_X509__
+        newCredential.privateData.encoding = OIC_ENCODING_BASE64;
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
         newCredential.publicData.data = NULL;
         newCredential.publicData.len = 0;
+        newCredential.publicData.encoding = OIC_ENCODING_RAW;
 #endif
         //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
         if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData,
@@ -852,6 +925,7 @@ static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
         }
         OIC_LOG(DEBUG, TAG, "Cred Payload:");
         OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+        OICFree(newCredential.eownerID);
 
         OCCallbackData cbData;
         cbData.cb = &SubOwnerCredentialHandler;
@@ -871,7 +945,7 @@ static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
         return OC_STACK_NO_RESOURCE;
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT PostSubOwnerCredential");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 
     return OC_STACK_OK;
 }
@@ -886,7 +960,7 @@ static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
  */
 static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
 {
-    OIC_LOG(INFO, TAG, "IN MOTDtlsHandshakeCB");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
     if(NULL != endpoint && NULL != info)
     {
@@ -913,24 +987,12 @@ static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t
                     //If temporal secure sesstion established successfully
                     if(CA_STATUS_OK == info->result)
                     {
-                        //Delete previous credential such as preconfigured-pin
-                        RemoveCredential(&(motCtx->selectedDeviceInfo->doxm->deviceID));
-
-                        res = SaveSubOwnerPSK(motCtx->selectedDeviceInfo);
-                        if(OC_STACK_OK == res)
+                        //POST sub owner credential to new device.
+                        res = PostSubOwnerCredential(motCtx);
+                        if(OC_STACK_OK != res)
                         {
-                            //POST sub owner credential to new device.
-                            res = PostSubOwnerCredential(motCtx);
-                            if(OC_STACK_OK != res)
-                            {
-                                OIC_LOG(ERROR, TAG,
-                                        "Failed to send POST request for SubOwner Credential");
-                                SetMOTResult(motCtx, res);
-                            }
-                        }
-                        else
-                        {
-                            OIC_LOG(ERROR, TAG, "Failed to save the SubOwner PSK.");
+                            OIC_LOG(ERROR, TAG,
+                                    "Failed to send POST request for SubOwner Credential");
                             SetMOTResult(motCtx, res);
                         }
                     }
@@ -974,20 +1036,45 @@ static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t
         }
     }
 
-    OIC_LOG(INFO, TAG, "OUT MOTDtlsHandshakeCB");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 }
 
 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
                                                     OCProvisionDev_t* selectedDevice)
 {
-    OIC_LOG(INFO, TAG, "IN StartMultipleOwnershipTransfer");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
     OCStackResult res = OC_STACK_INVALID_PARAM;
+    OicUuid_t myUuid = {.id={0}};
 
     VERIFY_NON_NULL(TAG, motCtx, ERROR);
     VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
     VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
     motCtx->selectedDeviceInfo = selectedDevice;
 
+    res = GetDoxmDeviceID(&myUuid);
+    if(OC_STACK_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to GetDoxmDeviceID");
+        SetMOTResult(motCtx, res);
+        return res;
+    }
+    if(memcmp(selectedDevice->doxm->owner.id, myUuid.id, sizeof(myUuid.id)) == 0)
+    {
+        res = OC_STACK_INVALID_DEVICE_INFO;
+        OIC_LOG(ERROR, TAG, "Owner cannot be registered as sub-owner.");
+        SetMOTResult(motCtx, res);
+        return res;
+    }
+    if (NULL == selectedDevice->doxm->mom ||
+        (selectedDevice->doxm->mom &&
+         OIC_MULTIPLE_OWNER_DISABLE == selectedDevice->doxm->mom->mode))
+    {
+        res = OC_STACK_NOT_ACCEPTABLE;
+        OIC_LOG(ERROR, TAG, "Selected device's MOT is disabled.");
+        SetMOTResult(motCtx, res);
+        return res;
+    }
+
     //Checking duplication of Device ID.
     char* strUuid = NULL;
     PdmDeviceState_t deviceState = PDM_DEVICE_UNKNOWN;
@@ -1076,7 +1163,7 @@ static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
     res = motCtx->otmCallback.createSecureSessionCB(motCtx);
     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
 
-    OIC_LOG(INFO, TAG, "OUT StartMultipleOwnershipTransfer");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 
 exit:
     return res;
@@ -1086,7 +1173,7 @@ OCStackResult MOTDoOwnershipTransfer(void* ctx,
                                      OCProvisionDev_t *selectedDevicelist,
                                      OCProvisionResultCB resultCallback)
 {
-    OIC_LOG(DEBUG, TAG, "IN MOTDoOwnershipTransfer");
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
     OCStackResult res = OC_STACK_INVALID_PARAM;
     OTMContext_t* motCtx = NULL;
     OCProvisionDev_t* pCurDev = NULL;
@@ -1125,10 +1212,10 @@ OCStackResult MOTDoOwnershipTransfer(void* ctx,
 
     motCtx->selectedDeviceInfo = selectedDevicelist;
     res = StartMultipleOwnershipTransfer(motCtx, selectedDevicelist);
-    VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
 
-    OIC_LOG(DEBUG, TAG, "OUT MOTDoOwnershipTransfer");
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 
+    return res;
 exit:
     if(OC_STACK_OK != res)
     {
@@ -1138,5 +1225,87 @@ exit:
             OICFree(motCtx);
         }
     }
+    OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, res);
+
     return res;
 }
+
+OCStackResult MOTRemoveSubOwner(void* ctx,
+                                const OCProvisionDev_t *targetDeviceInfo,
+                                const OicUuid_t* subOwner,
+                                OCProvisionResultCB resultCallback)
+{
+    OCStackResult deleteSubOwnerRes = OC_STACK_INVALID_CALLBACK;
+    OTMContext_t *motCtx = NULL;
+    char* strUuid = NULL;
+
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR);
+    deleteSubOwnerRes = OC_STACK_INVALID_PARAM;
+    VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
+    VERIFY_NON_NULL(TAG, subOwner, ERROR);
+
+    deleteSubOwnerRes = OC_STACK_NO_MEMORY;
+    //Generate the qurey to delete sub-owner
+    if (memcmp(subOwner->id, WILDCARD_SUBJECT_ID.id, sizeof(WILDCARD_SUBJECT_ID.id)) == 0)
+    {
+        strUuid = OICStrdup(WILDCARD_RESOURCE_URI);
+        VERIFY_NON_NULL(TAG, strUuid, ERROR);
+    }
+    else
+    {
+        VERIFY_SUCCESS(TAG, (OC_STACK_OK == ConvertUuidToStr(subOwner, &strUuid)), ERROR);
+    }
+    char url[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    snprintf(url, sizeof(url), "%s?%s=%s", OIC_RSRC_DOXM_URI, OIC_JSON_SUBOWNERID_NAME, strUuid);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    bool queryGenRes = PMGenerateQuery(true,
+                                       targetDeviceInfo->endpoint.addr,
+                                       targetDeviceInfo->securePort,
+                                       targetDeviceInfo->connType,
+                                       query, sizeof(query), url);
+    VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
+
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    //Create the MOT Context to handle the response message
+    motCtx = (OTMContext_t*)OICCalloc(1, sizeof(OTMContext_t));
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+    motCtx->selectedDeviceInfo= targetDeviceInfo;
+    motCtx->ctxResultCallback = resultCallback;
+    motCtx->ctxResultArraySize =1;
+    motCtx->ctxHasError = false;
+    motCtx->userCtx = ctx;
+    motCtx->ctxResultArray = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+    VERIFY_NON_NULL(TAG, motCtx->ctxResultArray, ERROR);
+
+    //Send POST request
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &MOTDeleteSecurityResourceCB;
+    cbData.context = (void *)motCtx;
+    OIC_LOG(DEBUG, TAG, "Sending DELETE sub-owner request to resource server");
+    deleteSubOwnerRes = OCDoResource(NULL, OC_REST_DELETE, query,
+                                     &targetDeviceInfo->endpoint, NULL,
+                                     targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == deleteSubOwnerRes), ERROR);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+
+    OICFree(strUuid);
+
+    return deleteSubOwnerRes;
+
+exit:
+    //If DELETE request successfully sent, motCtx will be cleaned from response handler.
+    OICFree(strUuid);
+    if (motCtx)
+    {
+        OICFree(motCtx->ctxResultArray);
+        OICFree(motCtx);
+    }
+    OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, deleteSubOwnerRes);
+    return deleteSubOwnerRes;
+}
+