IOT-1907: Fixing PMCloneOCProvisionDev, 43/17843/3
authorPawel Winogrodzki <pawelwi@microsoft.com>
Thu, 9 Mar 2017 21:57:05 +0000 (13:57 -0800)
committerKevin Kane <kkane@microsoft.com>
Thu, 16 Mar 2017 17:34:09 +0000 (17:34 +0000)
Fixing PMCloneOCProvisionDev to perform a proper deep copy
of the internal doxm::subOwners and doxm::mom fields, so that
they no longer point to the same structs as the original.

Change-Id: I5b30e4e7012934b9a17a4f8d7cecd6d2b65b1055
Signed-off-by: Pawel Winogrodzki <pawelwi@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17843
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Mike Fenelon <mike.fenelon@microsoft.com>
Reviewed-by: Alex Kelley <alexke@microsoft.com>
Reviewed-by: Kevin Kane <kkane@microsoft.com>
resource/csdk/security/provisioning/include/internal/pmutilityinternal.h [new file with mode: 0644]
resource/csdk/security/provisioning/src/multipleownershiptransfermanager.c
resource/csdk/security/provisioning/src/pmutility.c
resource/csdk/security/provisioning/unittest/otmunittest.cpp
resource/csdk/security/provisioning/unittest/pmutilitytest.cpp

diff --git a/resource/csdk/security/provisioning/include/internal/pmutilityinternal.h b/resource/csdk/security/provisioning/include/internal/pmutilityinternal.h
new file mode 100644 (file)
index 0000000..378a1b0
--- /dev/null
@@ -0,0 +1,71 @@
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef _PM_UTILITY_INTERNAL_H_
+#define _PM_UTILITY_INTERNAL_H_
+
+#include "pmtypes.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef MULTIPLE_OWNER
+/**
+ * Performs a deep copy of a single OicSecMom_t struct.
+ *
+ * @param[in] src    The source struct to be copied.
+ *
+ * @return   A pointer to the copy or NULL in case of an error.
+ */
+OicSecMom_t* CloneOicSecMom(const OicSecMom_t* src);
+
+/**
+ * Performs a deep copy of a single OicSecSubOwner_t struct.
+ *
+ * @param[in] src    The source struct to be copied.
+ *
+ * @return   A pointer to the copy or NULL in case of an error.
+ */
+OicSecSubOwner_t* CloneOicSecSubOwner(const OicSecSubOwner_t* src);
+#endif //MULTIPLE_OWNER
+
+/**
+ * Performs a deep copy of a single OicSecDoxm_t struct.
+ *
+ * @param[in] src    The source struct to be copied.
+ *
+ * @return   A pointer to the copy or NULL in case of an error.
+ */
+OicSecDoxm_t* CloneOicSecDoxm(const OicSecDoxm_t* src);
+
+/**
+ * API to perform a deep copy of a list of OCProvisionDev_t. The result must be
+ * freed using PMDeleteDeviceList.
+ *
+ * @param[in]   source  Source list to be cloned. Must not be null.
+ * @return  Cloned source or NULL in case of an error.
+ */
+OCProvisionDev_t* PMCloneOCProvisionDevList(const OCProvisionDev_t* source);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //_PM_UTILITY_INTERNAL_H_
index 45ee265..be2eb6f 100644 (file)
@@ -47,6 +47,7 @@
 #include "oxmjustworks.h"
 #include "pmtypes.h"
 #include "pmutility.h"
+#include "pmutilityinternal.h"
 #include "srmutility.h"
 #include "provisioningdatabasemanager.h"
 #include "oxmrandompin.h"
@@ -155,12 +156,13 @@ static OCStackResult MOTSendPostDoxm(void *ctx,
     VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
 
-    localTargetDeviceInfo = PMCloneOCProvisionDev(targetDeviceInfo);
-    VERIFY_NOT_NULL(TAG, localTargetDeviceInfo, ERROR);
-
     //Create the MOT Context to handle the response message
     motCtx = (OTMContext_t*)OICCalloc(1, sizeof(OTMContext_t));
     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
+
+    localTargetDeviceInfo = PMCloneOCProvisionDevList(targetDeviceInfo);
+    VERIFY_NOT_NULL(TAG, localTargetDeviceInfo, ERROR);
+
     motCtx->selectedDeviceInfo = localTargetDeviceInfo;
     motCtx->ctxResultCallback = resultCallback;
     motCtx->ctxResultArraySize = 1;
@@ -428,12 +430,13 @@ OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *target
     VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
 
-    localTargetDeviceInfo = PMCloneOCProvisionDev(targetDeviceInfo);
-    VERIFY_NOT_NULL(TAG, localTargetDeviceInfo, ERROR);
-
     //Create the MOT Context to handle the response message
     motCtx = (OTMContext_t*)OICCalloc(1, sizeof(OTMContext_t));
     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
+
+    localTargetDeviceInfo = PMCloneOCProvisionDevList(targetDeviceInfo);
+    VERIFY_NOT_NULL(TAG, localTargetDeviceInfo, ERROR);
+
     motCtx->selectedDeviceInfo= localTargetDeviceInfo;
     motCtx->ctxResultCallback = resultCallback;
     motCtx->ctxResultArraySize =1;
index 0d54ea0..da4f1db 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "pmtypes.h"
 #include "pmutility.h"
+#include "pmutilityinternal.h"
 
 #include "srmutility.h"
 
@@ -132,6 +133,116 @@ static OCStackApplicationResult SecVersionDiscoveryHandler(void *ctx, OCDoHandle
                                 OCClientResponse *clientResponse);
 #endif
 
+#ifdef MULTIPLE_OWNER
+OicSecMom_t* CloneOicSecMom(const OicSecMom_t* src)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+
+    if (!src)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
+        return NULL;
+    }
+
+    OicSecMom_t* newMom = (OicSecMom_t*)OICMalloc(sizeof(*newMom));
+    if (newMom)
+    {
+        *newMom = *src;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+
+    return newMom;
+}
+
+OicSecSubOwner_t* CloneOicSecSubOwner(const OicSecSubOwner_t* src)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+
+    if (!src)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
+        return NULL;
+    }
+
+    OicSecSubOwner_t* newSubOwner = (OicSecSubOwner_t*)OICCalloc(1, sizeof(*newSubOwner));
+    VERIFY_NOT_NULL(TAG, newSubOwner, ERROR);
+
+    memcpy(newSubOwner, src, sizeof(OicSecSubOwner_t));
+
+    if (src->next)
+    {
+        newSubOwner->next = CloneOicSecSubOwner(src->next);
+        VERIFY_NOT_NULL(TAG, newSubOwner->next, ERROR);
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+
+    return newSubOwner;
+
+exit:
+    OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
+    if (newSubOwner)
+    {
+        OICFree(newSubOwner);
+    }
+    return NULL;
+}
+#endif //MULTIPLE_OWNER
+
+OicSecDoxm_t* CloneOicSecDoxm(const OicSecDoxm_t* src)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+
+    if (!src)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
+        return NULL;
+    }
+
+    OicSecDoxm_t* newDoxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
+    VERIFY_NOT_NULL(TAG, newDoxm, ERROR);
+
+    memcpy(newDoxm, src, sizeof(OicSecDoxm_t));
+
+#ifdef MULTIPLE_OWNER
+    newDoxm->subOwners = NULL;
+    newDoxm->mom = NULL;
+
+    if (src->subOwners)
+    {
+        newDoxm->subOwners = CloneOicSecSubOwner(src->subOwners);
+        VERIFY_NOT_NULL(TAG, newDoxm->subOwners, ERROR);
+    }
+
+    if (src->mom)
+    {
+        newDoxm->mom = CloneOicSecMom(src->mom);
+        VERIFY_NOT_NULL(TAG, newDoxm->mom, ERROR);
+    }
+#endif //MULTIPLE_OWNER
+
+    // We have to assign NULL for not necessary information to prevent memory corruption.
+    newDoxm->oxmType = NULL;
+    newDoxm->oxmTypeLen = 0;
+    newDoxm->oxm = NULL;
+    newDoxm->oxmLen = 0;
+
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+
+    return newDoxm;
+
+exit:
+    OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
+    DeleteDoxmBinData(newDoxm);
+
+    return NULL;
+}
+
 /**
  * Function to search node in linked list that matches given IP and port.
  *
@@ -350,13 +461,8 @@ OCProvisionDev_t* PMCloneOCProvisionDev(const OCProvisionDev_t* src)
 
     if (src->doxm)
     {
-        newDev->doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
+        newDev->doxm = CloneOicSecDoxm(src->doxm);
         VERIFY_NOT_NULL(TAG, newDev->doxm, ERROR);
-
-        memcpy(newDev->doxm, src->doxm, sizeof(OicSecDoxm_t));
-        // We have to assign NULL for not necessary information to prevent memory corruption.
-        newDev->doxm->oxmType = NULL;
-        newDev->doxm->oxm = NULL;
     }
 
     if (0 == strlen(src->secVer))
@@ -379,12 +485,39 @@ OCProvisionDev_t* PMCloneOCProvisionDev(const OCProvisionDev_t* src)
 
 exit:
     OIC_LOG(ERROR, TAG, "PMCloneOCProvisionDev : Failed to allocate memory");
-    if (newDev)
+    PMDeleteDeviceList(newDev);
+    return NULL;
+}
+
+OCProvisionDev_t* PMCloneOCProvisionDevList(const OCProvisionDev_t* src)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+
+    if (!src)
     {
-        OICFree(newDev->pstat);
-        OICFree(newDev->doxm);
-        OICFree(newDev);
+        OIC_LOG_V(ERROR, TAG, "%s : Invalid parameter", __func__);
+        return NULL;
     }
+
+    OCProvisionDev_t* newDev = PMCloneOCProvisionDev(src);
+    VERIFY_NOT_NULL(TAG, newDev, ERROR);
+
+    OCProvisionDev_t* current = newDev;
+    for (OCProvisionDev_t* next = src->next; NULL != next; next = next->next)
+    {
+        current->next = PMCloneOCProvisionDev(next);
+        VERIFY_NOT_NULL(TAG, current->next, ERROR);
+
+        current = current->next;
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+
+    return newDev;
+
+exit:
+    OIC_LOG_V(ERROR, TAG, "%s : Failed to allocate memory", __func__);
+    PMDeleteDeviceList(newDev);
     return NULL;
 }
 
index ceff880..9e211d7 100644 (file)
@@ -816,4 +816,3 @@ TEST(FinalizeOTMTest, NullParam)
     int interpreter_res2 = system("pkill -f \"sample_server2\"");
     EXPECT_TRUE(0 <= interpreter_res2);
 }
-
index daacef7..cb07ba9 100644 (file)
  * *****************************************************************/
 #include "gtest/gtest.h"
 #include "pmutility.h"
+#include "pmutilityinternal.h"
+#include "doxmresource.h"
 #include "ocstack.h"
+#include "oic_malloc.h"
 #include "utlist.h"
 
 using namespace std;
@@ -37,6 +40,502 @@ extern OCStackResult AddDevice(OCProvisionDev_t **ppDevicesList, const char* add
 
 OCProvisionDev_t* gList = NULL;
 
+static bool UuidsIdentical(const OicUuid_t* first, const OicUuid_t* second)
+{
+    return (0 == memcmp(first, second, sizeof(OicUuid_t)));
+}
+
+#ifdef MULTIPLE_OWNER
+class CloneOicSecMomTest : public testing::Test
+{
+public:
+    CloneOicSecMomTest() :
+        m_originalStruct({OIC_MULTIPLE_OWNER_DISABLE}),
+        m_clonedStruct(NULL)
+    {}
+
+    void TearDown()
+    {
+        OICFree(m_clonedStruct);
+    }
+protected:
+
+    OicSecMom_t m_originalStruct;
+    OicSecMom_t* m_clonedStruct;
+};
+
+TEST(CloneOicSecMomSimpleTest, shouldReturnNullForNullInput)
+{
+    EXPECT_TRUE(NULL == CloneOicSecMom(NULL));
+}
+
+TEST_F(CloneOicSecMomTest, shouldReturnValidPointerForValidInput)
+{
+    m_clonedStruct = CloneOicSecMom(&m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct);
+}
+
+TEST_F(CloneOicSecMomTest, copyShouldHaveTheSameValueAsOriginal)
+{
+    m_clonedStruct = CloneOicSecMom(&m_originalStruct);
+    EXPECT_EQ(m_originalStruct.mode, m_clonedStruct->mode);
+}
+
+TEST_F(CloneOicSecMomTest, shouldReturnDifferentAddressThanOriginalForValidInput)
+{
+    m_clonedStruct = CloneOicSecMom(&m_originalStruct);
+    EXPECT_NE(&m_originalStruct, m_clonedStruct);
+}
+
+static OicSecSubOwner_t* BuildSampleOicSecSubOwner(MotStatus_t status,
+                                                   const OicUuid_t* uuid)
+{
+    OicSecSubOwner_t* result =
+        (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+    if (NULL == result)
+    {
+        return NULL;
+    }
+
+    result->status = status;
+    memcpy(&result->uuid, uuid, sizeof(OicUuid_t));
+    result->next = NULL;
+
+    return result;
+}
+
+static void FreeOicSecSubOwner(OicSecSubOwner_t* input)
+{
+    OicSecSubOwner_t* current = input;
+    OicSecSubOwner_t* temp = input;
+    while (NULL != current)
+    {
+        temp = current;
+        current = temp->next;
+        OICFree(temp);
+    }
+}
+
+class CloneOicSecSubOwnerTest : public testing::Test
+{
+public:
+    CloneOicSecSubOwnerTest() :
+        m_originalStruct(NULL),
+        m_clonedStruct(NULL)
+    {}
+
+    void SetUp()
+    {
+        m_originalStruct =
+            BuildSampleOicSecSubOwner(MOT_STATUS_READY, &s_sampleUuid);
+        ASSERT_FALSE(NULL == m_originalStruct);
+
+        m_originalStruct->next =
+            BuildSampleOicSecSubOwner(MOT_STATUS_IN_PROGRESS, &s_sampleNextUuid);
+        ASSERT_FALSE(NULL == m_originalStruct->next);
+    }
+
+    void TearDown()
+    {
+        FreeOicSecSubOwner(m_originalStruct);
+        FreeOicSecSubOwner(m_clonedStruct);
+    }
+protected:
+
+    static const OicUuid_t s_sampleUuid;
+    static const OicUuid_t s_sampleNextUuid;
+
+    OicSecSubOwner_t* m_originalStruct;
+    OicSecSubOwner_t* m_clonedStruct;
+};
+
+const OicUuid_t CloneOicSecSubOwnerTest::s_sampleUuid = {
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+const OicUuid_t CloneOicSecSubOwnerTest::s_sampleNextUuid = {
+    { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }
+};
+
+TEST(CloneOicSecSubOwnerSimpleTest, shouldReturnNullForNullInput)
+{
+    EXPECT_TRUE(NULL == CloneOicSecSubOwner(NULL));
+}
+
+TEST_F(CloneOicSecSubOwnerTest, shouldReturnValidPointerForValidInput)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct);
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyShouldHaveTheSameStatusAsOriginal)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_EQ(m_originalStruct->status, m_clonedStruct->status);
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyShouldHaveTheSameUuidAsOriginal)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_TRUE(UuidsIdentical(&m_originalStruct->uuid, &m_clonedStruct->uuid));
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyShouldHaveNext)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct->next);
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyNextShouldHaveTheSameStatusAsOriginal)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_EQ(m_originalStruct->next->status, m_clonedStruct->next->status);
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyNextShouldHaveTheSameUuidAsOriginal)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_TRUE(UuidsIdentical(&m_originalStruct->next->uuid,
+                               &m_clonedStruct->next->uuid));
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyShouldHaveDifferentAddressThanOriginal)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_NE(m_originalStruct, m_clonedStruct);
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyNextShouldHaveDifferentAddressThanOriginal)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_NE(m_originalStruct->next, m_clonedStruct->next);
+}
+
+TEST_F(CloneOicSecSubOwnerTest, copyShouldHaveNullLastNext)
+{
+    m_clonedStruct = CloneOicSecSubOwner(m_originalStruct);
+    EXPECT_TRUE(NULL == m_clonedStruct->next->next);
+}
+#endif
+
+class CloneOicSecDoxmTest : public testing::Test
+{
+public:
+    CloneOicSecDoxmTest() :
+        m_originalStruct(NULL),
+        m_clonedStruct(NULL)
+    {}
+
+    void SetUp()
+    {
+        m_originalStruct = BuildSampleOicSecDoxm();
+        ASSERT_FALSE(NULL == m_originalStruct);
+    }
+
+    void TearDown()
+    {
+        DeleteDoxmBinData(m_originalStruct);
+        DeleteDoxmBinData(m_clonedStruct);
+    }
+
+protected:
+
+    static const OicUuid_t s_sampleDeviceId;
+    static const OicUuid_t s_sampleOwner;
+    static const OicUuid_t s_sampleOwnerId;
+    static const OicUuid_t s_sampleSubOwner;
+
+    OicSecDoxm_t* m_originalStruct;
+    OicSecDoxm_t* m_clonedStruct;
+
+private:
+
+    OicSecDoxm_t* BuildSampleOicSecDoxm()
+    {
+        OicSecDoxm_t* result =
+            (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
+        if (NULL == result)
+        {
+            return NULL;
+        }
+
+        memcpy(&result->deviceID, &s_sampleDeviceId, sizeof(result->deviceID));
+        result->dpc = true;
+
+#ifdef MULTIPLE_OWNER
+        result->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+        if (NULL == result->mom)
+        {
+            return NULL;
+        }
+        result->mom->mode = OIC_MULTIPLE_OWNER_DISABLE;
+        result->subOwners =
+            BuildSampleOicSecSubOwner(MOT_STATUS_IN_PROGRESS, &s_sampleSubOwner);
+        if (NULL == result->subOwners)
+        {
+            return NULL;
+        }
+#endif
+
+        result->owned = true;
+        memcpy(&result->owner, &s_sampleOwner, sizeof(result->owner));
+        result->oxm = (OicSecOxm_t*)OICCalloc(1, sizeof(OicSecOxm_t));
+        if (NULL == result->oxm)
+        {
+            return NULL;
+        }
+        result->oxm[0] = OIC_JUST_WORKS;
+        result->oxmLen = 1U;
+        result->oxmSel = OIC_JUST_WORKS;
+        result->oxmType = (OicUrn_t*)OICCalloc(1, sizeof(OicUrn_t));
+        if (NULL == result->oxm)
+        {
+            return NULL;
+        }
+        result->oxmType[0] = NULL;
+        result->oxmTypeLen = 1U;
+        memcpy(&result->rownerID, &s_sampleOwnerId, sizeof(result->rownerID));
+        result->sct = NO_SECURITY_MODE;
+
+        return result;
+    }
+};
+
+const OicUuid_t CloneOicSecDoxmTest::s_sampleDeviceId = {
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+const OicUuid_t CloneOicSecDoxmTest::s_sampleOwner = {
+    { 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA }
+};
+
+const OicUuid_t CloneOicSecDoxmTest::s_sampleOwnerId = {
+    { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }
+};
+
+const OicUuid_t CloneOicSecDoxmTest::s_sampleSubOwner = {
+    { 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC }
+};
+
+TEST(CloneOicSecDoxmSimpleTest, shouldReturnNullForNullInput)
+{
+    EXPECT_TRUE(NULL == CloneOicSecDoxm(NULL));
+}
+
+TEST_F(CloneOicSecDoxmTest, shouldReturnValidPointerForValidInput)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveNulledOxmType)
+{
+    ASSERT_FALSE(NULL == m_originalStruct->oxmType);
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(NULL == m_clonedStruct->oxmType);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveZeroedOxmTypeLen)
+{
+    ASSERT_NE(0U, m_originalStruct->oxmTypeLen);
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_EQ(0U, m_clonedStruct->oxmTypeLen);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveNulledOxm)
+{
+    ASSERT_FALSE(NULL == m_originalStruct->oxm);
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(NULL == m_clonedStruct->oxm);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveZeroedOxmLen)
+{
+    ASSERT_NE(0U, m_originalStruct->oxmLen);
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_EQ(0U, m_clonedStruct->oxmLen);
+}
+
+#ifdef MULTIPLE_OWNER
+TEST_F(CloneOicSecDoxmTest, shouldReturnValidPointerForInputWithNullMom)
+{
+    OICFree(m_originalStruct->mom);
+    m_originalStruct->mom = NULL;
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveNonNullMom)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct->mom);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveDifferentMomAddress)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_NE(m_originalStruct->mom, m_clonedStruct->mom);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveNullMomForNullOriginal)
+{
+    OICFree(m_originalStruct->mom);
+    m_originalStruct->mom = NULL;
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(NULL == m_clonedStruct->mom);
+}
+
+TEST_F(CloneOicSecDoxmTest, shouldReturnValidPointerForInputWithNullSubOwners)
+{
+    FreeOicSecSubOwner(m_originalStruct->subOwners);
+    m_originalStruct->subOwners = NULL;
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveNonNullSubOwners)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_FALSE(NULL == m_clonedStruct->subOwners);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveDifferentSubOwnersAddress)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_NE(m_originalStruct->subOwners, m_clonedStruct->subOwners);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveNullSubOwnersForNullOriginal)
+{
+    FreeOicSecSubOwner(m_originalStruct->subOwners);
+    m_originalStruct->subOwners = NULL;
+
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(NULL == m_clonedStruct->subOwners);
+}
+#endif
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveTheSameDeviceIdAsOriginal)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(UuidsIdentical(&m_originalStruct->deviceID,
+                               &m_clonedStruct->deviceID));
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveTheSameOwnerIdAsOriginal)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(UuidsIdentical(&m_originalStruct->owner,
+                               &m_clonedStruct->owner));
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveTheSameRownerIdAsOriginal)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_TRUE(UuidsIdentical(&m_originalStruct->rownerID,
+                               &m_clonedStruct->rownerID));
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveTheSameSctAsOriginal)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_EQ(m_originalStruct->sct, m_clonedStruct->sct);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveTheSameOwnedAsOriginal)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_EQ(m_originalStruct->owned, m_clonedStruct->owned);
+}
+
+TEST_F(CloneOicSecDoxmTest, copyShouldHaveTheSameDpcAsOriginal)
+{
+    m_clonedStruct = CloneOicSecDoxm(m_originalStruct);
+    EXPECT_EQ(m_originalStruct->dpc, m_clonedStruct->dpc);
+}
+
+class CloneOCProvisionDevListTest : public ::testing::Test
+{
+public:
+    CloneOCProvisionDevListTest() :
+        m_originalStruct(NULL),
+        m_clonedStruct(NULL)
+    {}
+
+    void SetUp()
+    {
+        m_originalStruct = BuildSampleOCProvisionDev();
+        ASSERT_FALSE(NULL == m_originalStruct);
+
+        m_originalStruct->next = BuildSampleOCProvisionDev();
+        ASSERT_FALSE(NULL == m_originalStruct->next);
+    }
+
+    void TearDown()
+    {
+        PMDeleteDeviceList(m_originalStruct);
+        PMDeleteDeviceList(m_clonedStruct);
+    }
+protected:
+
+    OCProvisionDev_t* m_originalStruct;
+    OCProvisionDev_t* m_clonedStruct;
+
+private:
+
+    OCProvisionDev_t* BuildSampleOCProvisionDev()
+    {
+        return (OCProvisionDev_t*)OICCalloc(1, sizeof(OCProvisionDev_t));
+    }
+};
+
+TEST(CloneOCProvisionDevListSimpleTest, shouldReturnNullForNullInput)
+{
+    EXPECT_TRUE(NULL == PMCloneOCProvisionDevList(NULL));
+}
+
+TEST_F(CloneOCProvisionDevListTest, shouldReturnValidPointerForNonNullInput)
+{
+    m_clonedStruct = PMCloneOCProvisionDevList(m_originalStruct);
+
+    EXPECT_FALSE(NULL == m_clonedStruct);
+}
+
+TEST_F(CloneOCProvisionDevListTest, shouldReturnValidPointerForNonNext)
+{
+    m_clonedStruct = PMCloneOCProvisionDevList(m_originalStruct);
+
+    EXPECT_FALSE(NULL == m_clonedStruct->next);
+}
+
+TEST_F(CloneOCProvisionDevListTest, copyShouldHaveDifferentAddress)
+{
+    m_clonedStruct = PMCloneOCProvisionDevList(m_originalStruct);
+
+    EXPECT_NE(m_originalStruct, m_clonedStruct);
+}
+
+TEST_F(CloneOCProvisionDevListTest, copyShouldHaveDifferentAddressForNext)
+{
+    m_clonedStruct = PMCloneOCProvisionDevList(m_originalStruct);
+
+    EXPECT_NE(m_originalStruct->next, m_clonedStruct->next);
+}
+
+
 // List add Tests
 TEST(ProvisionListTest, Addition)
 {