[IOT-1763] CR 32 Device Onboarding State implementation 23/18723/12
authorNathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Fri, 14 Apr 2017 04:20:09 +0000 (21:20 -0700)
committerNathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Tue, 18 Apr 2017 22:03:53 +0000 (22:03 +0000)
Implementation of CR 32 "Device Offboarding and Soft Reset".

Note that there are a handful of minor updates still to be
done after the provisioning tool is fully updated, but this
can be done during QA cycle after merge to 1.3-rel. See [IOT-2023].

Note also that the unit tests are not written yet; however,
the critical onboarding path from RFOTM->RFPRO->RFNOP has been
verified using the provisioning tool sample app. See [IOT-2024].

patch set 2,3: rebase
patch set 4,5: address review comments
patch set 6,7: fix jenkins issues
patch set 8: rebase
patch set 9: fix jenkins issues
patch set 10: rebase
patsh set 11: address review comments

Change-Id: I7dc8adb5ad90bd168f3ab485461568b9ab7805e0
Signed-off-by: Nathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/18723
Reviewed-by: Kevin Kane <kkane@microsoft.com>
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
13 files changed:
resource/csdk/security/SConscript
resource/csdk/security/include/internal/deviceonboardingstate.h [new file with mode: 0644]
resource/csdk/security/include/internal/doxmresource.h
resource/csdk/security/include/internal/pstatresource.h
resource/csdk/security/include/srmutility.h
resource/csdk/security/provisioning/src/ownershiptransfermanager.c
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/credresource.c
resource/csdk/security/src/deviceonboardingstate.c [new file with mode: 0644]
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/policyengine.c
resource/csdk/security/src/pstatresource.c
resource/csdk/security/src/srmutility.c

index dcb4f78..346ea1e 100644 (file)
@@ -118,7 +118,8 @@ libocsrm_src = [
        OCSRM_SRC + 'srmutility.c',
        OCSRM_SRC + 'iotvticalendar.c',
        OCSRM_SRC + 'base64.c',
-       OCSRM_SRC + 'directpairing.c'
+       OCSRM_SRC + 'directpairing.c',
+       OCSRM_SRC + 'deviceonboardingstate.c'
        ]
 
 if libocsrm_env.get('SECURED') == '1':
diff --git a/resource/csdk/security/include/internal/deviceonboardingstate.h b/resource/csdk/security/include/internal/deviceonboardingstate.h
new file mode 100644 (file)
index 0000000..86ca59c
--- /dev/null
@@ -0,0 +1,61 @@
+//******************************************************************
+//
+// Copyright 2017 Intel OpenSource Technology Center All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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 DEVICEONBOARDINGSTATE_H_
+#define DEVICEONBOARDINGSTATE_H_
+
+#include "octypes.h"
+#include "securevirtualresourcetypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get the current Device Onboarding State (pstat.dos).
+ *
+ * @param[out] dos Pointer to contain the values of current state (pstat.dos)
+ *
+ * @return  ::OC_STACK_OK If no errors and dos is filled in successfully.
+            ::OC_STACK_ERROR If dos is NOT filled in successfully.
+ */
+OCStackResult GetDos(OicSecDostype_t *dos);
+
+/**
+ * Set the Device Onboarding State (pstat.dos) to a new state.
+ *
+ * Note that all requirements for entering new state should typically be set
+ * prior to making this call, typically by the Onboarding Tool (OBT).  The
+ * exceptions are Properties that are set by the Server itself.  See
+ * OCF Security Specification, Security Resources chapters for details.
+ *
+ * @param[in] state Value of new desired state (pstat.dos.state)
+ *
+ * @return  ::OC_STACK_OK if successful change to newState
+ *          ::OC_STACK_FORBIDDEN_REQ if state change preconditions not met
+ *          ::OC_STACK_INTERNAL_SERVER_ERROR if SVRs left in potentially unstable state
+ */
+OCStackResult SetDosState(const OicSecDeviceOnboardingState_t state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DEVICEONBOARDINGSTATE_H_ */
index e389618..4b3e64c 100644 (file)
@@ -95,43 +95,69 @@ OCStackResult SetDoxmDeviceIDSeed(const uint8_t* seed, size_t seedSize);
 #endif
 
 /**
- * This method returns the SRM device ID for this device.
+ * Get the doxm.deviceuuid value for this device.
  *
- * @return ::OC_STACK_OK for Success, otherwise some error value.
+ * @param[out] deviceuuid ptr to contain a copy of doxm.deviceuuid value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID);
+OCStackResult GetDoxmDeviceID(OicUuid_t *deviceuuid);
 
 /**
- * This method changes the SRM device ID for this device.
- * This api will update device Id iff device is in unowned state.
- * @return ::OC_STACK_OK for Success, otherwise some error value.
+ * Set the doxm.deviceuuid value for this device.
+ *
+ * @param[in] deviceuuid ptr to value to be copied into doxm.deviceuuid.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceuuid);
+
+/**
+ * Get the doxm.devowneruuid value for this device.
+ *
+ * @param[out] devowneruuid ptr to contain a copy of doxm.devowneruuid value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID);
+OCStackResult GetDoxmDevOwnerId(OicUuid_t *devowneruuid);
 
 /**
- * Gets the OicUuid_t value for the owner of this device.
+ * Set the doxm.deviceuuid value for this device.
  *
- * @param devownerid a pointer to be assigned to the devownerid property
- * @return ::OC_STACK_OK if devownerid is assigned correctly, else ::OC_STACK_ERROR.
+ * @param[in] deviceuuid ptr to value to be copied into doxm.deviceuuid.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-OCStackResult GetDoxmDevOwnerId(OicUuid_t *devownerid);
+OCStackResult SetDoxmDevOwnerId(const OicUuid_t *devowneruuid);
 
 /**
- * Gets the bool state of "isOwned" property on the doxm resource.
+ * Get the doxm.isowned value for this device.
  *
- * @param isOwned a pointer to be assigned to isOwned property
- * @return ::OC_STACK_OK if isOwned is assigned correctly, else ::OC_STACK_ERROR.
+ * @param[out] isowned ptr to contain a copy of doxm.isowned value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-OCStackResult GetDoxmIsOwned(bool *isOwned);
+OCStackResult GetDoxmIsOwned(bool *isowned);
 
 /**
- * Gets the OicUuid_t value for the rowneruuid of the doxm resource.
+ * Set the doxm.isowned value for this device.
  *
- * @param rowneruuid a pointer to be assigned to the rowneruuid property
- * @return ::OC_STACK_OK if rowneruuid is assigned correctly, else ::OC_STACK_ERROR.
+ * @param[in] isowned ptr to value to be copied into doxm.isowned.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetDoxmIsOwned(const bool isowned);
+
+/**
+ * Get the doxm.rowneruuid value for this device.
+ *
+ * @param[out] rowneruuid ptr to contain a copy of rowneruuid value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
 OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid);
 
+/**
+ * Set the doxm.rowneruuid value for this device.
+ *
+ * @param[in] rowneruuid ptr to value to be copied into doxm.rowneruuid.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetDoxmRownerId(const OicUuid_t *rowneruuid);
+
 #ifdef MULTIPLE_OWNER
 /**
  * Compare the UUID to SubOwner.
@@ -196,7 +222,7 @@ OCStackResult SetDoxmSelfOwnership(const OicUuid_t* newROwner);
  * struct with the values from another /oic/sec/doxm struct.
  *
  * @param src is a pointer to the source @ref OicSecDoxm_t data.
- * @param dst is a pointer to the destination @ref OicSecDoxm_t data. 
+ * @param dst is a pointer to the destination @ref OicSecDoxm_t data.
  *
  * @retval ::OC_STACK_OK for Success, otherwise some error value
  */
index 5ccc94a..e0af37c 100644 (file)
@@ -78,28 +78,100 @@ void DeletePstatBinData(OicSecPstat_t* pstat);
 void RestorePstatToInitState();
 
 /**
- * Internal function to update resource owner
+ * Get the pstat.rowneruuid value for this device.
  *
- * @param newROwner new owner
+ * @param[out] rowneruuid ptr to contain a copy of pstat.rowneruuid value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid);
+
+/**
+ * Set the pstat.rowneruuid value for this device.
  *
- * @retval ::OC_STACK_OK for Success, otherwise some error value
+ * @param[in] rowneruuid ptr to value to be copied into pstat.rowneruuid.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-OCStackResult SetPstatRownerId(const OicUuid_t* newROwner);
+OCStackResult SetPstatRownerId(const OicUuid_t* rowneruuid);
 
 /**
- * Gets the OicUuid_t value for the rownerid of the pstat resource.
+ * Get the pstat.dos.s value for this device.
  *
- * @param rowneruuid a pointer to be assigned to the rowneruuid property
- * @return ::OC_STACK_OK if rowneruuid is assigned correctly, else ::OC_STACK_ERROR.
+ * @param[out] s ptr to contain a copy of pstat.dos.s value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid);
+OCStackResult GetPstatDosS(OicSecDeviceOnboardingState_t *s);
+
+/**
+ * Set the pstat.dos.s value for this device.
+ *
+ * @param[in] s value to be copied into pstat.dos.s.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetPstatDosS(const OicSecDeviceOnboardingState_t s);
+
+/**
+ * Get the pstat.dos.p value for this device.
+ *
+ * @param[out] p ptr to contain a copy of pstat.dos.p value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult GetPstatDosP(bool *p);
+
+/**
+ * Set the pstat.dos.p value for this device.
+ *
+ * @param[in] p value to be copied into pstat.dos.p.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetPstatDosP(const bool p);
+
+/**
+ * Get the pstat.isop value for this device.
+ *
+ * @param[out] isop ptr to contain a copy of pstat.isop value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult GetPstatIsop(bool *isop);
+
+/**
+ * Set the pstat.isop value for this device.
+ *
+ * @param[in] isop value to be copied into pstat.isop.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetPstatIsop(const bool isop);
+
+/**
+ * Get the pstat.cm value for this device.
+ *
+ * @param[out] cm ptr to contain a copy of pstat.cm value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult GetPstatCm(OicSecDpm_t *cm);
+
+/**
+ * Set the pstat.cm value for this device.
+ *
+ * @param[in] cm value to be copied into pstat.cm.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult SetPstatCm(const OicSecDpm_t cm);
+
+/**
+ * Get the pstat.tm value for this device.
+ *
+ * @param[out] tm ptr to contain a copy of pstat.tm value.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
+ */
+OCStackResult GetPstatTm(OicSecDpm_t *tm);
 
 /**
- * This function returns the "isop" status of the device.
+ * Set the pstat.tm value for this device.
  *
- * @return true iff pstat.isop == 1, else false
+ * @param[in] tm value to be copied into pstat.tm.
+ * @return ::OC_STACK_OK if value is copied successfully, else ::OC_STACK_ERROR.
  */
-bool GetPstatIsop();
+OCStackResult SetPstatTm(const OicSecDpm_t tm);
 
 /**
  * Internal function to change pastat resource to Ready for Normal Operation.
index 4bd55eb..72c3242 100644 (file)
@@ -62,6 +62,15 @@ struct OicParseQueryIter
 #define VERIFY_SUCCESS(tag, op, logLevel) do{ if (!(op)) \
             {OIC_LOG((logLevel), tag, #op " failed!!"); goto exit; } }while(0)
 
+/**
+ * Macro to verify expression evaluates to bool true.
+ * eg: VERIFY_TRUE(TAG, OC_STACK_OK == foo(), ERROR);
+ * @note Invoking function must define "exit:" label for goto functionality to work correctly.
+ */
+#define VERIFY_TRUE(tag, op, logLevel) do{ if (!(op)) \
+            {OIC_LOG_V((logLevel), tag, "%s:" #op "evaluates to false!",__func__); \
+            goto exit; } }while(0)
+
 /**
  * Macro to verify success of operation.
  * eg: VERIFY_SUCCESS_RETURN(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
@@ -135,6 +144,21 @@ OCStackResult ConvertUuidToStr(const OicUuid_t* uuid, char** strUuid);
  */
 OCStackResult ConvertStrToUuid(const char* strUuid, OicUuid_t* uuid);
 
+/**
+ * Compares two OicUuid_t structs.
+ *
+ * @return true if the two OicUuid_t structs are equal, else false.
+ */
+bool UuidCmp(const OicUuid_t *firstId, const OicUuid_t *secondId);
+
+extern const OicUuid_t THE_NIL_UUID;
+
+/**
+ * OicUuid_t to Nil UUID {.id={0000000000000000}}
+ *
+ * @return true if the OicUuid_t is the Nil UUID
+ */
+bool IsNilUuid(const OicUuid_t *uuid);
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 /**
index 808b639..67a9931 100644 (file)
@@ -2489,8 +2489,8 @@ OCStackResult PostNormalOperationStatus(OTMContext_t* otmCtx)
         return OC_STACK_INVALID_PARAM;
     }
 
-    //Set isop to true.
-    otmCtx->selectedDeviceInfo->pstat->isOp = true;
+    // TODO [IOT-1763] put RFPRO and other pstat.dos.s updates in the right places.
+    otmCtx->selectedDeviceInfo->pstat->dos.state = DOS_RFNOP;
 
     OCSecurityPayload *secPayload = (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload));
     if (!secPayload)
@@ -2549,11 +2549,19 @@ OCStackResult ConfigSelfOwnership(void)
         OIC_LOG (ERROR, TAG, "Unable to retrieve doxm owned state");
         return OC_STACK_ERROR;
     }
-    if( (true == isDeviceOwned) ||(true == GetPstatIsop()) )
+
+    bool isop = false;
+    if (OC_STACK_OK != GetPstatIsop(&isop))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to get pstat.isop.");
+        return OC_STACK_ERROR;
+    }
+    if (isDeviceOwned || isop )
     {
         OIC_LOG(ERROR, TAG, "The state of device is not Ready for Ownership transfer.");
         return OC_STACK_ERROR;
     }
+
     OicUuid_t deviceID = {.id={0}};
     if ( OC_STACK_OK != GetDoxmDeviceID(&deviceID) )
     {
index 11c3037..5b23380 100644 (file)
@@ -2371,8 +2371,8 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
     OicSecRsrc_t* credRsrc = NULL;
     OicSecRsrc_t* rolesRsrc = NULL;
 
-    /* 
-     * Note that all Ace_t and Rsrc_t objects will be freed on error by 
+    /*
+     * Note that all Ace_t and Rsrc_t objects will be freed on error by
      * DeleteACLList(acl). We LL_APPEND these objects to the acl object as soon
      * as they are allocated.
      */
@@ -2538,7 +2538,7 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
     memcpy(&fullPermAce->subjectuuid, &WILDCARD_SUBJECT_ID, sizeof(fullPermAce->subjectuuid));
 
     // Resources -- Mandatory
-    // /oic/sec/roles 
+    // /oic/sec/roles
     rolesRsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
     VERIFY_NOT_NULL(TAG, rolesRsrc, ERROR);
     LL_APPEND(fullPermAce->resources, rolesRsrc);
@@ -3096,11 +3096,10 @@ exit:
 
 OCStackResult GetAclRownerId(OicUuid_t *rowneruuid)
 {
-    OCStackResult retVal = OC_STACK_ERROR;
-    if (gAcl)
+    if (gAcl && rowneruuid)
     {
-        *rowneruuid = gAcl->rownerID;
-        retVal = OC_STACK_OK;
+        memcpy(&(rowneruuid->id), &(gAcl->rownerID.id), sizeof(rowneruuid->id));
+        return OC_STACK_OK;
     }
-    return retVal;
+    return OC_STACK_ERROR;
 }
index f315057..9044f22 100644 (file)
@@ -770,7 +770,7 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
 
             cborEncoderResult = cbor_encode_text_string(&roleIdMap, OIC_JSON_ROLE_NAME, strlen(OIC_JSON_ROLE_NAME));
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role tag");
-            
+
             cborEncoderResult = cbor_encode_text_string(&roleIdMap, cred->roleId.id, strlen(cred->roleId.id));
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role value");
 
@@ -2967,13 +2967,12 @@ exit:
 
 OCStackResult GetCredRownerId(OicUuid_t *rowneruuid)
 {
-    OCStackResult retVal = OC_STACK_ERROR;
-    if (gCred)
+    if (gCred && rowneruuid)
     {
-        *rowneruuid = gCred->rownerID;
-        retVal = OC_STACK_OK;
+        memcpy(&(rowneruuid->id), &(gCred->rownerID.id), sizeof(rowneruuid->id));
+        return OC_STACK_OK;
     }
-    return retVal;
+    return OC_STACK_ERROR;
 }
 
 #if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
diff --git a/resource/csdk/security/src/deviceonboardingstate.c b/resource/csdk/security/src/deviceonboardingstate.c
new file mode 100644 (file)
index 0000000..1d789b6
--- /dev/null
@@ -0,0 +1,623 @@
+//******************************************************************
+//
+// Copyright 2017 Intel OpenSource Technology Center All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "deviceonboardingstate.h"
+#include "srmutility.h"
+#include "octypes.h"
+#include "logger.h"
+#include "securevirtualresourcetypes.h"
+#include "srmresourcestrings.h"
+#include "aclresource.h"
+#include "amaclresource.h"
+#include "credresource.h"
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#include "crlresource.h"
+#endif /* (__WITH_DTLS__) || (__WITH_TLS__) */
+#include "doxmresource.h"
+#include "pstatresource.h"
+
+#define TAG "OIC_SRM_DOS"
+
+/**
+ * @return true if changing from oldState to newState is valid transition.
+ */
+static bool IsValidStateTransition(OicSecDeviceOnboardingState_t oldState,
+    OicSecDeviceOnboardingState_t newState)
+{
+    bool ret = false;
+
+    switch (newState)
+    {
+        case DOS_RESET:
+        ret = true;
+        break;
+
+        case DOS_RFNOP:
+        if (DOS_RFPRO == oldState)
+        {
+            ret = true;
+        }
+        break;
+
+        case DOS_RFOTM:
+        if (DOS_RESET == oldState)
+        {
+            ret = true;
+        }
+        break;
+
+        case DOS_RFPRO:
+        if (DOS_RFNOP == oldState
+            || DOS_RFOTM == oldState
+            || DOS_SRESET == oldState)
+        {
+            ret = true;
+        }
+        break;
+
+        case DOS_SRESET:
+        if (DOS_RFNOP == oldState
+            || DOS_RFPRO == oldState)
+        {
+            ret = true;
+        }
+        break;
+    }
+
+    OIC_LOG_V(INFO, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * @return true if Device meets requirements to enter RFNOP DOS.
+ */
+static bool IsReadyToEnterRFNOP()
+{
+    bool ret = false;
+    bool tempBool = false;
+    OicUuid_t tempUuid = {.id={0}};
+
+    // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
+
+    // Verify doxm.owned == TRUE.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
+    VERIFY_TRUE(TAG, tempBool, WARNING);
+
+    // Verify doxm.devowneruuid != nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Verify doxm.deviceuuid != nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Verify oxmsel was the actual OTM used (no-op: CTT will verify this during
+    // certification testing, as it requires OBT cooperation to verify).
+
+    // Verify pstat.isop == false (Server sets isop on entry)
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatIsop(&tempBool), ERROR);
+    VERIFY_TRUE(TAG, !tempBool, WARNING);
+
+    // Verify implemented SVRs with rowneruuid Property have non-Nil rowneruuid
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetAclRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCredRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Verify each rowneruuid, devowneruuid has a corresponding /cred entry
+    // TODO [IOT-2023]
+
+    ret = true;
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * @return true if Device meets requirements to enter RFOTM DOS.
+ */
+static bool IsReadyToEnterRFOTM()
+{
+    bool ret = false;
+    bool tempBool = false;
+    OicUuid_t tempUuid = {.id={0}};
+
+    // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
+
+    // Verify doxm.owned == FALSE.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
+    VERIFY_TRUE(TAG, !tempBool, WARNING);
+
+    // Verify doxm.devowneruuid == nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Check and log whether doxm.deviceuuid == nil UUID ("may" reqt not "shall")
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
+    if (!IsNilUuid(&tempUuid))
+    {
+        OIC_LOG_V(INFO, TAG, "%s: doxm.deviceuuid != Nil UUID... allowed but noted.",
+            __func__);
+    }
+
+    ret = true;
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * @return true if Device meets requirements to enter RFPRO DOS.
+ */
+static bool IsReadyToEnterRFPRO()
+{
+    bool ret = false;
+    bool tempBool = false;
+    OicUuid_t tempUuid = {.id={0}};
+
+    // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
+
+    // Verify doxm.owned == TRUE.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
+    VERIFY_TRUE(TAG, tempBool, WARNING);
+
+    // Verify doxm.devowneruuid != nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Verify doxm.deviceuuid != nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // doxm.sct and doxm.oxmsel retain previous values (checked by CTT)
+
+    // Verify implemented SVRs with rowneruuid Property have non-Nil rowneruuid
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetAclRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCredRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatRownerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Verify each rowneruuid, devowneruuid has a corresponding /cred entry
+    // TODO [IOT-2023]
+
+    ret = true;
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * @return true if Device meets requirements to set pstat.dos.s = SRESET.
+ */
+static bool IsReadyToEnterSRESET()
+{
+    bool ret = false;
+    bool tempBool = false;
+    OicUuid_t tempUuid = {.id={0}};
+
+    // Note: pstat.dos.p set by DoStateChange(), so not checked here.
+
+    // TODO [IOT-2023]: sanity check SVRs (optional)
+
+    // Verify doxm.owned == TRUE.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
+    VERIFY_TRUE(TAG, tempBool, WARNING);
+
+    // Verify doxm.devowneruuid != nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // Verify doxm.deviceuuid != nil UUID.
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
+    VERIFY_TRUE(TAG, !IsNilUuid(&tempUuid), WARNING);
+
+    // doxm.sct and doxm.oxmsel retain previous values (checked by CTT)
+
+    ret = true;
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Generic ops performed on entering most states, coalesced to avoid repeat code.
+ */
+static bool EnterStateGeneric(bool isop,
+                              bool cmReset,
+                              bool cmTakeOwner,
+                              bool tmReset,
+                              bool tmTakeOwner,
+                              OicSecDeviceOnboardingState_t state)
+{
+    bool ret = false;
+    OicSecDpm_t cm = 0;
+    OicSecDpm_t tm = 0;
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatCm(&cm), ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatTm(&tm), ERROR);
+
+    // Set pstat.isop
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatIsop(isop), ERROR);
+
+    // Set pstat.cm
+    if (cmReset)
+    {
+        cm |= RESET; // set RESET bit
+    }
+    else
+    {
+        cm &= ~RESET; // clear RESET bit
+    }
+    if (cmTakeOwner)
+    {
+        cm |= TAKE_OWNER; // set TAKE_OWNER bit
+    }
+    else
+    {
+        cm &= ~TAKE_OWNER; // clear TAKE_OWNER bit
+    }
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatCm(cm), ERROR);
+
+    // Set pstat.tm
+    if (tmReset)
+    {
+        tm |= RESET; // set RESET bit
+    }
+    else
+    {
+        tm &= ~RESET; // clear RESET bit
+    }
+    if (tmTakeOwner)
+    {
+        tm |= TAKE_OWNER; // set TAKE_OWNER bit
+    }
+    else
+    {
+        tm &= ~TAKE_OWNER; // clear TAKE_OWNER bit
+    }
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatTm(tm), ERROR);
+
+    // Set pstat.dos.s
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosS(state), ERROR);
+
+    ret = true;
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Enter RFNOP state and set all Server-controlled SVR Property values.
+ */
+static bool EnterRFNOP()
+{
+    bool ret = false;
+
+    // Set pstat.isop = TRUE
+    // Unset pstat.cm RESET and TAKE_OWNER bits
+    // Unset pstat.tm RESET and TAKE_OWNER bits
+    // Set pstat.dos to RFNOP
+    ret = EnterStateGeneric(true, false, false, false, false, DOS_RFNOP);
+
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Enter RFOTM state and set all Server-controlled SVR Property values.
+ */
+static bool EnterRFOTM()
+{
+    bool ret = false;
+
+    // Set pstat.isop = FALSE
+    // Unset pstat.cm RESET bit, and set TAKE_OWNER bit
+    // Unset pstat.tm RESET and TAKE_OWNER bits
+    // Set pstat.dos to RFOTM
+    ret = EnterStateGeneric(false, false, true, false, false, DOS_RFOTM);
+
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Enter RFPRO state and set all Server-controlled SVR Property values.
+ */
+static bool EnterRFPRO()
+{
+    bool ret = false;
+
+    // Set pstat.isop = FALSE
+    // Unset pstat.cm RESET and TAKE_OWNER bits
+    // Unset pstat.tm RESET and TAKE_OWNER bits
+    // Set pstat.dos to RFPRO
+    ret = EnterStateGeneric(false, false, false, false, false, DOS_RFPRO);
+
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Enter RESET state and set all Server-controlled SVR Property values.
+ */
+static bool EnterRESET()
+{
+    bool ret = false;
+
+    // Restore Mfr Defaults
+    // TODO [IOT-2023]: we need OSWG Security TG to decide on how "mfr defaults"
+    // should really work.  Hard coded SVRs?  Backup .dat file?  Hard coded
+    // policy without SVRs?  IMO this is *highly* platform and mfr process
+    // dependent and probably isn't worth investing the time to create an
+    // IoTivity "backup/restore" capability.  Instead the need to do so should
+    // be documented in the device vendor certification paperwork, per BZ 1383.
+
+    // Set doxm.deviceuuid = Mfr Default (handled above)
+    // Set doxm.sct = Mfr Default ("")
+    // Set doxm.oxmsel = Mfr Default ("")
+    // Set pstat.om = Mfr Default ("")
+    // Set pstat.sm = Mfr Default ("")
+    // Assert acl2, amacl, sacl, cred arrays = mfr defaults ("")
+
+    // Set doxm.owned = FALSE
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmIsOwned(false), ERROR);
+
+    // Set doxm.devowneruuid = Nil UUID
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmDevOwnerId(&THE_NIL_UUID), ERROR);
+
+    // Set acl, doxm, cred and pstat rowneruuids = Nil UUID
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetAclRownerId(&THE_NIL_UUID), ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetCredRownerId(&THE_NIL_UUID), ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmRownerId(&THE_NIL_UUID), ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatRownerId(&THE_NIL_UUID), ERROR);
+
+    // Set pstat.isop = FALSE
+    // Set pstat.cm RESET and unset TAKE_OWNER
+    // Unset pstat.tm and set TAKE_OWNER
+    // Set pstat.dos.s to RESET
+    VERIFY_SUCCESS(TAG,
+        EnterStateGeneric(false, true, false, false, false, DOS_RESET),
+        ERROR);
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Enter SRESET state and set all Server-controlled SVR Property values.
+ */
+static bool EnterSRESET()
+{
+    bool ret = false;
+
+    // Set pstat.isop = FALSE
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatIsop(false), ERROR);
+
+    // Set pstat.dos to SRESET
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosS(DOS_SRESET), ERROR);
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+/**
+ * Set pstat.dos.p (pending) to true, then verify device is ready to perform
+ * the state change.  If so, perform the state change.  Finally, set
+ * pstat.dos.p (pending) to false.
+ * @return  OC_STACK_OK if successful change to newState
+ *          OC_STACK_FORBIDDEN_REQ if state change preconditions not met
+ *          OC_STACK_INTERNAL_SERVER_ERROR if SVRs left in potentially unstable state
+ */
+static OCStackResult DoStateChange(OicSecDeviceOnboardingState_t newState)
+{
+    OCStackResult ret = OC_STACK_INTERNAL_SERVER_ERROR;
+
+    switch (newState)
+    {
+        case DOS_RESET:
+        // No preconditions other than setting dos.p = true, which is done above
+        if (EnterRESET())
+        {
+            ret = OC_STACK_OK;
+        }
+        else
+        {
+            ret = OC_STACK_INTERNAL_SERVER_ERROR;
+        }
+        break;
+
+        case DOS_RFNOP:
+        if (IsReadyToEnterRFNOP())
+        {
+            if (EnterRFNOP())
+            {
+                ret = OC_STACK_OK;
+            }
+            else
+            {
+                ret = OC_STACK_INTERNAL_SERVER_ERROR;
+            }
+        }
+        else
+        {
+            ret = OC_STACK_FORBIDDEN_REQ;
+        }
+        break;
+
+        case DOS_RFOTM:
+        if (IsReadyToEnterRFOTM())
+        {
+            if (EnterRFOTM())
+            {
+                ret = OC_STACK_OK;
+            }
+            else
+            {
+                ret = OC_STACK_INTERNAL_SERVER_ERROR;
+            }
+        }
+        else
+        {
+            ret = OC_STACK_FORBIDDEN_REQ;
+        }
+        break;
+
+        case DOS_RFPRO:
+        if (IsReadyToEnterRFPRO())
+        {
+            if (EnterRFPRO())
+            {
+                ret = OC_STACK_OK;
+            }
+            else
+            {
+                ret = OC_STACK_INTERNAL_SERVER_ERROR;
+            }
+        }
+        else
+        {
+            ret = OC_STACK_FORBIDDEN_REQ;
+        }
+        break;
+
+        case DOS_SRESET:
+        if (IsReadyToEnterSRESET())
+        {
+            if (EnterSRESET())
+            {
+                ret = OC_STACK_OK;
+            }
+            else
+            {
+                ret = OC_STACK_INTERNAL_SERVER_ERROR;
+            }
+        }
+        else
+        {
+            ret = OC_STACK_FORBIDDEN_REQ;
+        }
+        break;
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %d.", __func__, ret);
+    return ret;
+}
+
+OCStackResult GetDos(OicSecDostype_t *dos)
+{
+    if (dos)
+    {
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosS(&(dos->state)), ERROR);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosP(&(dos->pending)), ERROR);
+        return OC_STACK_OK;
+    }
+exit:
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetDosState(const OicSecDeviceOnboardingState_t desiredState)
+{
+    OIC_LOG_V(INFO, TAG, "%s called for state %d.", __func__, desiredState);
+
+    OCStackResult ret = OC_STACK_ERROR;
+    bool pending = false;
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosP(&pending), ERROR);
+
+    if (!pending)
+    {
+
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosP(true), ERROR);
+
+        OicSecDeviceOnboardingState_t oldState = DOS_RESET;
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosS(&oldState), ERROR);
+        if (IsValidStateTransition(oldState, desiredState))
+        {
+            OCStackResult stateChangeResult = DoStateChange(desiredState);
+            switch (stateChangeResult)
+            {
+                case OC_STACK_OK:
+                OIC_LOG_V(INFO, TAG, "%s: DOS state changed SUCCESSFULLY from %d to %d.", \
+                    __func__, oldState, desiredState);
+                ret = OC_STACK_OK;
+                break;
+
+                case OC_STACK_FORBIDDEN_REQ:
+                OIC_LOG_V(WARNING, TAG, "%s: DOS state change change from %d to %d NOT ALLOWED.", \
+                    __func__, oldState, desiredState);
+                ret = OC_STACK_FORBIDDEN_REQ;
+                break;
+
+                case OC_STACK_INTERNAL_SERVER_ERROR:
+                default:
+                OIC_LOG_V(ERROR, TAG, "%s: DOS state change change from %d to %d FAILED. \
+                    Internal error - SVRs may be in bad state.", \
+                    __func__, oldState, desiredState);
+                ret = OC_STACK_INTERNAL_SERVER_ERROR;
+                break;
+            }
+        }
+        else
+        {
+            OIC_LOG_V(INFO, TAG, "%s: Invalid transition; cannot go from %d to %d.", \
+                __func__, oldState, desiredState);
+            ret = OC_STACK_FORBIDDEN_REQ;
+        }
+
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosP(false), ERROR);
+
+    }
+    else
+    {
+        OIC_LOG_V(WARNING, TAG, "%s: cannot set pstat->dos.s, change \
+            already pending.", __func__);
+        ret = OC_STACK_FORBIDDEN_REQ;
+    }
+
+    // TODO [IOT-2023] implement RESET->RFOTM change once supported by prov tool
+
+    // TODO [IOT-2023] if OC_STACK_OK, update all SVRs in Persistent Storage?
+
+    return ret;
+
+exit:
+    return OC_STACK_INTERNAL_SERVER_ERROR;
+}
\ No newline at end of file
index 805c5e7..b112e75 100644 (file)
@@ -1825,26 +1825,6 @@ OCStackResult DeInitDoxmResource()
     }
 }
 
-OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID)
-{
-    if (deviceID && gDoxm)
-    {
-       *deviceID = gDoxm->deviceID;
-        return OC_STACK_OK;
-    }
-    return OC_STACK_ERROR;
-}
-
-OCStackResult GetDoxmIsOwned(bool *isOwned)
-{
-    if (isOwned && gDoxm)
-    {
-       *isOwned = gDoxm->owned;
-        return OC_STACK_OK;
-    }
-    return OC_STACK_ERROR;
-}
-
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 OCStackResult SetDoxmDeviceIDSeed(const uint8_t* seed, size_t seedSize)
 {
@@ -1875,11 +1855,21 @@ OCStackResult SetDoxmDeviceIDSeed(const uint8_t* seed, size_t seedSize)
 }
 #endif
 
-OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
+OCStackResult GetDoxmDeviceID(OicUuid_t *deviceuuid)
+{
+    if (deviceuuid && gDoxm)
+    {
+        *deviceuuid = gDoxm->deviceID;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceuuid)
 {
     bool isOwnerUpdated = false;
     bool isRownerUpdated = false;
-    if (NULL == deviceID)
+    if (NULL == deviceuuid)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -1905,36 +1895,36 @@ OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
     memcpy(prevUuid.id, gDoxm->deviceID.id, sizeof(prevUuid.id));
 
     //Change the device UUID
-    memcpy(gDoxm->deviceID.id, deviceID->id, sizeof(deviceID->id));
+    memcpy(gDoxm->deviceID.id, deviceuuid->id, sizeof(gDoxm->deviceID.id));
 
     //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));
+        memcpy(gDoxm->owner.id, deviceuuid->id, sizeof(gDoxm->owner.id));
         isOwnerUpdated = true;
     }
     //Change the resource owner ID if necessary
+    // TODO [IOT-2023] change this behavior and upate the usage of this function
+    // so that rowneruuid for each resource is set by OBT
     if (memcmp(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id)) == 0)
     {
-        memcpy(gDoxm->rownerID.id, deviceID->id, sizeof(deviceID->id));
+        memcpy(gDoxm->rownerID.id, deviceuuid->id, sizeof(gDoxm->rownerID.id));
         isRownerUpdated = true;
     }
-    // TODO: T.B.D Change resource owner for pstat, acl and cred
 
     //Update PS
     if (!UpdatePersistentStorage(gDoxm))
     {
         //revert UUID in case of PSI error
-        memcpy(gDoxm->deviceID.id, prevUuid.id, sizeof(prevUuid.id));
+        memcpy(gDoxm->deviceID.id, prevUuid.id, sizeof(gDoxm->deviceID.id));
         if (isOwnerUpdated)
         {
-            memcpy(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id));
+            memcpy(gDoxm->owner.id, prevUuid.id, sizeof(gDoxm->owner.id));
         }
         if (isRownerUpdated)
         {
-            memcpy(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id));
+            memcpy(gDoxm->rownerID.id, prevUuid.id, sizeof(gDoxm->rownerID.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;
@@ -1942,34 +1932,64 @@ OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
     return OC_STACK_OK;
 }
 
-OCStackResult GetDoxmDevOwnerId(OicUuid_t *devownerid)
+OCStackResult GetDoxmDevOwnerId(OicUuid_t *devowneruuid)
+{
+    if (gDoxm && devowneruuid)
+    {
+        memcpy(&(devowneruuid->id), &(gDoxm->owner.id), sizeof(devowneruuid->id));
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetDoxmDevOwnerId(const OicUuid_t *devowneruuid)
+{
+    if (gDoxm && devowneruuid)
+    {
+        memcpy(&(gDoxm->owner.id), &(devowneruuid->id), sizeof(gDoxm->owner.id));
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult GetDoxmIsOwned(bool *isowned)
+{
+    if (isowned && gDoxm)
+    {
+        *isowned = gDoxm->owned;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetDoxmIsOwned(const bool isowned)
 {
-    OCStackResult retVal = OC_STACK_ERROR;
     if (gDoxm)
     {
-        OIC_LOG_V(DEBUG, TAG, "GetDoxmDevOwnerId(): gDoxm owned =  %d.", \
-            gDoxm->owned);
-        if (gDoxm->owned)
-        {
-            *devownerid = gDoxm->owner;
-            retVal = OC_STACK_OK;
-        }
+        gDoxm->owned = isowned;
+        return OC_STACK_OK;
     }
-    return retVal;
+    return OC_STACK_ERROR;
 }
 
 OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid)
 {
-    OCStackResult retVal = OC_STACK_ERROR;
-    if (gDoxm)
+    if (gDoxm && rowneruuid)
     {
-        if( gDoxm->owned )
-        {
-            *rowneruuid = gDoxm->rownerID;
-                    retVal = OC_STACK_OK;
-        }
+        memcpy(&(rowneruuid->id), &(gDoxm->rownerID.id), sizeof(rowneruuid->id));
+        return OC_STACK_OK;
     }
-    return retVal;
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetDoxmRownerId(const OicUuid_t *rowneruuid)
+{
+    if (gDoxm && rowneruuid)
+    {
+        memcpy(&(gDoxm->rownerID.id), &(rowneruuid->id), sizeof(gDoxm->rownerID.id));
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
 }
 
 #ifdef MULTIPLE_OWNER
index 8f44f11..052bed4 100644 (file)
@@ -70,33 +70,6 @@ uint16_t GetPermissionFromCAMethod_t(const CAMethod_t method)
     return perm;
 }
 
-/**
- * Compares two OicUuid_t structs.
- *
- * @return true if the two OicUuid_t structs are equal, else false.
- */
-static bool UuidCmp(OicUuid_t *firstId, OicUuid_t *secondId)
-{
-    // TODO use VERIFY macros to check for null when they are merged.
-    if(NULL == firstId || NULL == secondId)
-    {
-        return false;
-    }
-    // Check empty uuid string
-    if('\0' == firstId->id[0] || '\0' == secondId->id[0])
-    {
-        return false;
-    }
-    for(int i = 0; i < UUID_LENGTH; i++)
-    {
-        if(firstId->id[i] != secondId->id[i])
-        {
-            return false;
-        }
-    }
-    return true;
-}
-
 /**
  * Compare the request's subject to DevOwner.
  *
@@ -508,17 +481,18 @@ void CheckPermission(SRMRequestContext_t *context)
     // (which in IoTivity is equivalent to isOp == false && owned == false)
     // AND c) the request is for a SVR resource.
     // If all 3 conditions are met, grant request.
-    // TODO_IoTivity_1.3: use pstat.dos instead of these two checks.
+    // TODO_IoTivity_1.3 [IOT-2023] use pstat.dos instead of these two checks.
     bool isDeviceOwned = true; // default to value that will NOT grant access
-    if (OC_STACK_OK != GetDoxmIsOwned(&isDeviceOwned)) // if runtime error, don't grant
-    {
-        OIC_LOG(ERROR, TAG, "GetDoxmIsOwned() call failed.");
-        context->responseVal = ACCESS_DENIED_POLICY_ENGINE_ERROR;
-    }
-    // If we were able to get the value of doxm->isOwned, proceed with
-    // test for implicit access.
-    else if (IsRequestFromDevOwner(context) &&  // if from DevOwner
-            !GetPstatIsop() &&                  // AND if pstat->isOp == false
+    bool isop = false;
+
+    context->responseVal = ACCESS_DENIED_POLICY_ENGINE_ERROR;
+
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatIsop(&isop), ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&isDeviceOwned), ERROR);
+
+    // Test for implicit access.
+    if (IsRequestFromDevOwner(context) &&       // if from DevOwner
+            !isop &&                            // AND if pstat->isOp == false
             !isDeviceOwned &&                   // AND if doxm->isOwned == false
             (NOT_A_SVR_RESOURCE != context->resourceType)) // AND if is SVR type
     {
@@ -544,7 +518,7 @@ void CheckPermission(SRMRequestContext_t *context)
         }
     }
 #endif //MULTIPLE_OWNER
-    else if (!GetPstatIsop() &&
+    else if (!isop &&
              (NOT_A_SVR_RESOURCE != context->resourceType) &&
              IsRequestFromOwnershipTransferSession(context))
     {
@@ -582,5 +556,6 @@ void CheckPermission(SRMRequestContext_t *context)
         }
     }
 
+exit:
     return;
 }
index e127112..5dcb978 100644 (file)
@@ -32,6 +32,7 @@
 #include "psinterface.h"
 #include "srmresourcestrings.h"
 #include "srmutility.h"
+#include "deviceonboardingstate.h"
 
 #define TAG  "OIC_SRM_PSTAT"
 
@@ -43,7 +44,7 @@ static const uint16_t CBOR_SIZE = 512;
 static const uint16_t CBOR_MAX_SIZE = 4400;
 
 // PSTAT Map size - Number of read-write items +2 for rt and if.
-// TODO [IOT-1958] isOp becomes read-only; -1 here
+// TODO [IOT-2023] isOp becomes read-only; -1 here
 static const uint8_t PSTAT_MIN_MAP_SIZE = 7; // dos, isOp, tm, om, rowneruuid, rt, if
 
 // .dos Property map size
@@ -51,7 +52,7 @@ static const uint8_t PSTAT_DOS_MAP_SIZE = 2; // s, p
 
 // Number of read-only Properties, added to map if not creating a writable-only
 // representation.
-// TODO [IOT-1958] isOp becomes read-only; +1 here
+// TODO [IOT-2023] isOp becomes read-only; +1 here
 static const uint8_t READ_ONLY_PROPERTY_SIZE = 2; // cm, sm
 
 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
@@ -193,7 +194,7 @@ OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload,
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing pstat.dos map");
 
     // isop Property
-    // TODO [IOT-1958] move isOp inside !writableOnly check
+    // TODO [IOT-2023] move isOp inside !writableOnly check
     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
         strlen(OIC_JSON_ISOP_NAME));
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
@@ -371,10 +372,10 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
     if (CborInvalidType != pstatMap.type)
     {
         // found pstat.dos tag "dos" in pstatMap
-        OIC_LOG(INFO, TAG, "Found pstat.dos tag in pstatMap.");
+        OIC_LOG(DEBUG, TAG, "Found pstat.dos tag in pstatMap.");
         if (CborNoError == cborFindResult && cbor_value_is_container(&pstatMap))
         {
-            OIC_LOG(INFO, TAG, "Found pstat.dos cbor container; entering.");
+            OIC_LOG(DEBUG, TAG, "Found pstat.dos cbor container; entering.");
             cborFindResult = cbor_value_enter_container(&pstatMap, &dosMap);
             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering dos map.");
         }
@@ -389,20 +390,20 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
             {
                 if (strcmp(dosTagName, OIC_JSON_S_NAME) == 0)
                 {
-                    OIC_LOG(INFO, TAG, "Found pstat.dos.s tag; getting int value.");
+                    OIC_LOG(DEBUG, TAG, "Found pstat.dos.s tag; getting int value.");
                     int s = -1;
                     cborFindResult = cbor_value_get_int(&dosMap, &s);
                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting pstat.dos.s value.");
-                    OIC_LOG_V(INFO, TAG, "Read pstat.dos.s value = %d.", s);
+                    OIC_LOG_V(DEBUG, TAG, "Read pstat.dos.s value = %d.", s);
                     pstat->dos.state = (OicSecDeviceOnboardingState_t)s;
                 }
                 else if (strcmp(dosTagName, OIC_JSON_P_NAME) == 0)
                 {
-                    OIC_LOG(INFO, TAG, "Found pstat.dos.p tag; getting boolean value.");
+                    OIC_LOG(DEBUG, TAG, "Found pstat.dos.p tag; getting boolean value.");
                     bool p = false;
                     cborFindResult = cbor_value_get_boolean(&dosMap, &p);
                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting pstat.dos.p value.");
-                    OIC_LOG_V(INFO, TAG, "Read pstat.dos.p value = %s.", p?"true":"false");
+                    OIC_LOG_V(DEBUG, TAG, "Read pstat.dos.p value = %s.", p?"true":"false");
                     pstat->dos.pending = p;
                 }
                 else
@@ -439,7 +440,7 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
         cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
 
-        // TODO [IOT-1958] will make this Property read-only... for now, leave
+        // TODO [IOT-2023] will make this Property read-only... for now, leave
         // as writable
         // if (roParsed)
         // {
@@ -661,6 +662,8 @@ static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRe
         bool roParsed = false;
         OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
         VERIFY_NOT_NULL(TAG, pstat, ERROR);
+
+        // if CBOR parsing OK
         if (OC_STACK_OK == ret)
         {
             bool validReq = false;
@@ -699,10 +702,10 @@ static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRe
                 ehRet = OC_EH_BAD_REQ;
                 goto exit;
             }
-            validReq = false;
+            // validReq = false;
 
             // Currently, IoTivity only supports Single Service Client Directed provisioning
-            // TODO [IOT-1763]: update this state management logic as part of CR 32.
+            // TODO [IOT-2023]: update this state management logic once prov tool is updated
             if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
             {
                 if ((pstat->cm & RESET) && false == pstat->isOp)
@@ -753,12 +756,69 @@ static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRe
                 goto exit;
             }
 
-            // TODO [IOT-1763]: use SetState() function on dos as part of CR 32.
-            gPstat->dos.state = pstat->dos.state;
-            gPstat->dos.pending = pstat->dos.pending;
-            gPstat->isOp = pstat->isOp;
+            OCStackResult stateChangeResult = OC_STACK_ERROR;
+            // TODO [IOT-2023] temporary fix until prov tool is updated -
+            // insert change to RFPRO before changing to RFNOP.
+            if (DOS_RFNOP == pstat->dos.state)
+            {
+                stateChangeResult = SetDosState(DOS_RFPRO);
+                switch (stateChangeResult)
+                {
+                    case OC_STACK_OK:
+                    OIC_LOG_V(INFO, TAG, "%s: DOS state changed SUCCESSFULLY to %d.", \
+                        __func__, pstat->dos.state);
+                    ehRet = OC_EH_OK;
+                    break;
+
+                    case OC_STACK_FORBIDDEN_REQ:
+                    OIC_LOG_V(WARNING, TAG, "%s: DOS state change change to %d NOT ALLOWED.", \
+                        __func__, pstat->dos.state);
+                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                    goto exit;
+                    break;
+
+                    case OC_STACK_INTERNAL_SERVER_ERROR:
+                    default:
+                    OIC_LOG_V(ERROR, TAG, "%s: DOS state change change to %d FAILED. \
+                        Internal error - SVRs may be in bad state.", \
+                        __func__, pstat->dos.state);
+                    ehRet = OC_EH_INTERNAL_SERVER_ERROR;
+                    goto exit;
+                    break;
+                }
+            }
+
+            if(OC_EH_OK == ehRet)
+            {
+                stateChangeResult = SetDosState(pstat->dos.state);
+                switch (stateChangeResult)
+                {
+                    case OC_STACK_OK:
+                    OIC_LOG_V(INFO, TAG, "%s: DOS state changed SUCCESSFULLY to %d.", \
+                        __func__, pstat->dos.state);
+                    ehRet = OC_EH_OK;
+                    break;
+
+                    case OC_STACK_FORBIDDEN_REQ:
+                    OIC_LOG_V(WARNING, TAG, "%s: DOS state change change to %d NOT ALLOWED.", \
+                        __func__, pstat->dos.state);
+                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                    goto exit;
+                    break;
+
+                    case OC_STACK_INTERNAL_SERVER_ERROR:
+                    default:
+                    OIC_LOG_V(ERROR, TAG, "%s: DOS state change change to %d FAILED. \
+                        Internal error - SVRs may be in bad state.", \
+                        __func__, pstat->dos.state);
+                    ehRet = OC_EH_INTERNAL_SERVER_ERROR;
+                    goto exit;
+                    break;
+                }
+            }
+
+            // [IOT-2023] remove once provisioning tool updated
             gPstat->tm = pstat->tm;
-            gPstat->cm = pstat->tm; // TODO [IOT-1763]: remove once dos state is functional
             gPstat->om = pstat->om;
             memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
 
@@ -789,6 +849,8 @@ static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRe
 
     exit:
 
+    // TODO [IOT-1796] This is another place error code returns need to be
+    // cleaned up.
     if (OC_EH_OK != ehRet)
     {
         /*
@@ -913,6 +975,9 @@ OCStackResult InitPstatResource()
     }
     VERIFY_NOT_NULL(TAG, gPstat, FATAL);
 
+    // TODO [IOT-2023]: after all SVRs are initialized, need to call SetDosState()
+    // using the just-loaded pstat.dos.s
+
     // Instantiate 'oic.sec.pstat'
     ret = CreatePstatResource();
 
@@ -960,14 +1025,24 @@ void RestorePstatToInitState()
     }
 }
 
-OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
+OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
+{
+    if (gPstat && rowneruuid)
+    {
+        memcpy(&(rowneruuid->id), &(gPstat->rownerID.id), sizeof(rowneruuid->id));
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetPstatRownerId(const OicUuid_t *rowneruuid)
 {
     OCStackResult ret = OC_STACK_ERROR;
     uint8_t *cborPayload = NULL;
     size_t size = 0;
     OicUuid_t prevId = {.id={0}};
 
-    if(NULL == newROwner)
+    if(NULL == rowneruuid)
     {
         ret = OC_STACK_INVALID_PARAM;
     }
@@ -976,10 +1051,10 @@ OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
         ret = OC_STACK_NO_RESOURCE;
     }
 
-    if(newROwner && gPstat)
+    if(rowneruuid && gPstat)
     {
         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
-        memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
+        memcpy(gPstat->rownerID.id, rowneruuid->id, sizeof(gPstat->rownerID.id));
 
         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
@@ -994,29 +1069,108 @@ OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
 
 exit:
     OICFree(cborPayload);
-    memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
+    memcpy(gPstat->rownerID.id, prevId.id, sizeof(gPstat->rownerID.id));
     return ret;
 }
 
-/**
- * This function returns the "isop" status of the device.
- *
- * @return true iff pstat.isop == 1, else false
- */
-bool GetPstatIsop()
+OCStackResult GetPstatDosS(OicSecDeviceOnboardingState_t *s)
 {
-    return gPstat->isOp;
+    if (gPstat && s)
+    {
+        *s = gPstat->dos.state;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
 }
 
-OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
+OCStackResult SetPstatDosS(const OicSecDeviceOnboardingState_t s)
+{
+    if (gPstat)
+    {
+        gPstat->dos.state = s;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult GetPstatDosP(bool *p)
+{
+    if (gPstat && p)
+    {
+        *p = gPstat->dos.pending;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetPstatDosP(const bool p)
+{
+    if (gPstat)
+    {
+        gPstat->dos.pending = p;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult GetPstatIsop(bool *isop)
+{
+    if (gPstat && isop)
+    {
+        *isop = gPstat->isOp;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetPstatIsop(const bool isop)
+{
+    if (gPstat)
+    {
+        gPstat->isOp = isop;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult GetPstatCm(OicSecDpm_t *cm)
+{
+    if (gPstat && cm)
+    {
+        *cm = gPstat->cm;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetPstatCm(const OicSecDpm_t cm)
+{
+    if (gPstat)
+    {
+        gPstat->cm = cm;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult GetPstatTm(OicSecDpm_t *tm)
+{
+    if (gPstat && tm)
+    {
+        *tm = gPstat->tm;
+        return OC_STACK_OK;
+    }
+    return OC_STACK_ERROR;
+}
+
+OCStackResult SetPstatTm(const OicSecDpm_t tm)
 {
-    OCStackResult retVal = OC_STACK_ERROR;
     if (gPstat)
     {
-        *rowneruuid = gPstat->rownerID;
-        retVal = OC_STACK_OK;
+        gPstat->tm = tm;
+        return OC_STACK_OK;
     }
-    return retVal;
+    return OC_STACK_ERROR;
 }
 
 OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
index cac74fd..b5a4b6f 100644 (file)
@@ -163,6 +163,40 @@ OCStackResult ConvertStrToUuid(const char* strUuid, OicUuid_t* uuid)
     return OC_STACK_OK;
 }
 
+
+/**
+ * Compares two OicUuid_t structs.
+ *
+ * @return true if the two OicUuid_t structs are equal, else false.
+ */
+bool UuidCmp(const OicUuid_t *firstId, const OicUuid_t *secondId)
+{
+    bool ret = false;
+    VERIFY_NOT_NULL(TAG, firstId, ERROR);
+    VERIFY_NOT_NULL(TAG, secondId, ERROR);
+
+    if (0 == memcmp(firstId, secondId, sizeof(OicUuid_t)))
+    {
+        ret = true;
+    }
+
+exit:
+    OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
+    return ret;
+}
+
+const OicUuid_t THE_NIL_UUID = {.id={0000000000000000}};
+
+/**
+ * Compares OicUuid_t to Nil UUID {.id={0000000000000000}}
+ *
+ * @return true if the OicUuid_t is the Nil UUID.
+ */
+bool IsNilUuid(const OicUuid_t *uuid)
+{
+    return UuidCmp(uuid, &THE_NIL_UUID);
+}
+
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 OCStackResult SetDeviceIdSeed(const uint8_t* seed, size_t seedSize)
 {