[IOT-1801] Implement OCF Security CR1339
authorDan Mihai <Daniel.Mihai@microsoft.com>
Tue, 14 Feb 2017 23:04:11 +0000 (15:04 -0800)
committerKevin Kane <kkane@microsoft.com>
Tue, 21 Feb 2017 16:50:00 +0000 (16:50 +0000)
1. Use the initial Ownership Transfer session even after setting-up
   the Owner Credential, when onboarding Servers based on OCF 1.0 -
   rather than closing that session and establishing a new one.

2. Posting the Owner Credential ACL might fail for older Servers.
   In that case, close the initial Ownership Transfer session and
   establish a new session, for compatibility with those older
   Servers.

Change-Id: If242c0af4ec05ad9ca144c274ee5385bc7738d92
Signed-off-by: Dan Mihai <Daniel.Mihai@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17279
Reviewed-by: Kevin Kane <kkane@microsoft.com>
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/api/casecurityinterface.h
resource/csdk/connectivity/inc/ca_adapter_net_ssl.h
resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c
resource/csdk/connectivity/src/caconnectivitymanager.c
resource/csdk/connectivity/test/ssladapter_test.cpp
resource/csdk/security/provisioning/include/pmtypes.h
resource/csdk/security/provisioning/src/ownershiptransfermanager.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/policyengine.c

index a952477..089f67b 100755 (executable)
@@ -324,9 +324,17 @@ typedef struct
     // TODO change name to deviceId
     CARemoteId_t identity;      /**< endpoint device uuid */
     CARemoteId_t userId;        /**< endpoint user uuid */
+    uint32_t attributes;
 } CASecureEndpoint_t;
 
 /**
+ * Endpoint used for security administration - a special type of identity that
+ * bypasses Access Control Entry checks for SVR resources, while the device is
+ * not owned yet.
+ */
+#define CA_SECURE_ENDPOINT_ATTRIBUTE_ADMINISTRATOR  0x1
+
+/**
  * Enums for CA return values.
  */
 typedef enum
index 8a39fc8..1318d2d 100644 (file)
@@ -77,7 +77,27 @@ typedef int (*CAgetPskCredentialsHandler)(CADtlsPskCredType_t type,
  */
 const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer);
 #endif //MULTIPLE_OWNER
-#endif
+
+/**
+ * Adds a bit to the attributes field of a secure endpoint.
+ *
+ * @param[in]  peer         remote address
+ * @param[in]  newAttribute bit to be added to the attributes field
+ *
+ * @return  true if the secure endpoint has been found, false otherwise.
+ */
+bool CASetSecureEndpointAttribute(const CAEndpoint_t* peer, uint32_t newAttribute);
+
+/**
+ * Gets the attributes field of a secure endpoint.
+ *
+ * @param[in]  peer          remote address
+ * @param[out] allAttributes all the attributes bits for that remote address
+ *
+ * @return  true if the secure endpoint has been found, false otherwise.
+ */
+bool CAGetSecureEndpointAttributes(const CAEndpoint_t* peer, uint32_t* allAttributes);
+#endif // #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
 
 /**
  * This internal callback is used by CA layer to
index cad229d..e6098d8 100644 (file)
@@ -190,6 +190,26 @@ CAResult_t CAsslGenerateOwnerPsk(const CAEndpoint_t *endpoint,
 const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer);
 #endif
 
+/**
+ * Adds a bit to the attributes field of a secure endpoint.
+ *
+ * @param[in]  peer         remote address
+ * @param[in]  newAttribute bit to be added to the attributes field
+ *
+ * @return  true if the secure endpoint has been found, false otherwise.
+ */
+bool SetCASecureEndpointAttribute(const CAEndpoint_t* peer, uint32_t newAttribute);
+
+/**
+ * Gets the attributes field of a secure endpoint.
+ *
+ * @param[in]  peer          remote address
+ * @param[out] allAttributes all the attributes bits for that remote address
+ *
+ * @return  true if the secure endpoint has been found, false otherwise.
+ */
+bool GetCASecureEndpointAttributes(const CAEndpoint_t* peer, uint32_t* allAttributes);
+
 #ifdef __cplusplus
 }
 #endif //__cplusplus
index d8a7a89..fcb4a0c 100644 (file)
@@ -939,6 +939,91 @@ const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer)
 #endif
 
 /**
+ * Adds a bit to the attributes field of a secure endpoint.
+ *
+ * @param[in]  peer         remote address
+ * @param[in]  newAttribute bit to be added to the attributes field
+ *
+ * @return  true if the secure endpoint has been found, false otherwise.
+ */
+bool SetCASecureEndpointAttribute(const CAEndpoint_t* peer, uint32_t newAttribute)
+{
+    bool result = false;
+
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s(peer = %s:%u, attribute = %#x)", __func__,
+        peer->addr, (uint32_t)peer->port, newAttribute);
+
+    oc_mutex_lock(g_sslContextMutex);
+
+    if (NULL == g_caSslContext)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Context is NULL");
+    }
+    else
+    {
+        SslEndPoint_t* sslPeer = GetSslPeer(peer);
+
+        if (!sslPeer)
+        {
+            OIC_LOG(ERROR, NET_SSL_TAG, "SSL peer not found");
+        }
+        else
+        {
+            sslPeer->sep.attributes |= newAttribute;
+            result = true;
+        }
+    }
+
+    oc_mutex_unlock(g_sslContextMutex);
+
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s -> %s", __func__, result ? "success" : "failed");
+    return result;
+}
+
+/**
+ * Gets the attributes field of a secure endpoint.
+ *
+ * @param[in]  peer          remote address
+ * @param[out] allAttributes all the attributes bits for that remote address
+ *
+ * @return  true if the secure endpoint has been found, false otherwise.
+ */
+bool GetCASecureEndpointAttributes(const CAEndpoint_t* peer, uint32_t* allAttributes)
+{
+    bool result = false;
+
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s(peer = %s:%u)", __func__,
+        peer->addr, (uint32_t)peer->port);
+
+    oc_mutex_lock(g_sslContextMutex);
+
+    if (NULL == g_caSslContext)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Context is NULL");
+    }
+    else
+    {
+        SslEndPoint_t* sslPeer = GetSslPeer(peer);
+
+        if (!sslPeer)
+        {
+            OIC_LOG(ERROR, NET_SSL_TAG, "SSL peer not found");
+        }
+        else
+        {
+            *allAttributes = sslPeer->sep.attributes;
+            result = true;
+        }
+    }
+
+    oc_mutex_unlock(g_sslContextMutex);
+
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s -> %s, attributes = %#x", __func__,
+        result ? "success" : "failed", result ? *allAttributes : 0);
+    return result;
+}
+
+/**
  * Deletes cached message.
  *
  * @param[in]  msg    message
@@ -1792,9 +1877,9 @@ static void SendCacheMessages(SslEndPoint_t * tep)
 
 void CAsetSslHandshakeCallback(CAErrorCallback tlsHandshakeCallback)
 {
-    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s(%p)", __func__, tlsHandshakeCallback);
     g_sslCallback = tlsHandshakeCallback;
-    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s(%p)", __func__, tlsHandshakeCallback);
 }
 
 /* Read data from TLS connection
index b0bd2e9..b2e680c 100644 (file)
@@ -155,6 +155,42 @@ const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer)
 }
 #endif //MULTIPLE_OWNER
 
+bool CASetSecureEndpointAttribute(const CAEndpoint_t* peer, uint32_t attribute)
+{
+    bool success = false;
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    if (!g_isInitialized)
+    {
+        OIC_LOG(DEBUG, TAG, "CA is not initialized");
+    }
+    else
+    {
+        success = SetCASecureEndpointAttribute(peer, attribute);
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s -> %u", __func__, (uint32_t)success);
+    return success;
+}
+
+bool CAGetSecureEndpointAttributes(const CAEndpoint_t* peer, uint32_t* attributes)
+{
+    bool success = false;
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    if (!g_isInitialized)
+    {
+        OIC_LOG(DEBUG, TAG, "CA is not initialized");
+    }
+    else
+    {
+        success = GetCASecureEndpointAttributes(peer, attributes);
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s -> %u", __func__, (uint32_t)success);
+    return success;
+}
+
 CAResult_t CAregisterSslHandshakeCallback(CAErrorCallback tlsHandshakeCallback)
 {
     OIC_LOG(DEBUG, TAG, "CAregisterSslHandshakeCallback");
index 7dd65ca..15fec8c 100644 (file)
@@ -37,6 +37,8 @@
 #ifdef MULTIPLE_OWNER
 #define GetCASecureEndpointData GetCASecureEndpointDataTest
 #endif
+#define SetCASecureEndpointAttribute SetCASecureEndpointAttributeTest
+#define GetCASecureEndpointAttributes GetCASecureEndpointAttributesTest
 
 #include "../src/adapter_util/ca_adapter_net_ssl.c"
 
index 8581cc0..a1f8fb6 100644 (file)
@@ -70,9 +70,10 @@ typedef struct OCProvisionDev
 #ifdef WITH_TCP
     uint16_t        tcpPort;         /**< tcp port **/
 #endif
-    char             secVer[OIC_SEC_MAX_VER_LEN];         /**< security version **/
+    char            secVer[OIC_SEC_MAX_VER_LEN];         /**< security version **/
     DeviceStatus    devStatus;       /**< status of device **/
-    OCDoHandle    handle;
+    OCDoHandle      handle;
+    bool            ownerAclUnauthorizedRequest;        /**< true if the provisioning client has already re-tried posting the Owner ACE **/
     struct OCProvisionDev  *next;    /**< Next pointer. **/
 }OCProvisionDev_t;
 
index c0d94f8..51b7812 100755 (executable)
@@ -1144,27 +1144,24 @@ static OCStackApplicationResult OwnerCredentialHandler(void *ctx, OCDoHandle UNU
 
     if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
     {
-        if(otmCtx && otmCtx->selectedDeviceInfo)
+        if(otmCtx->selectedDeviceInfo)
         {
-            //Close the temporal secure session to verify the owner credential
+            //For Servers based on OCF 1.0, PostOwnerAcl can be executed using
+            //the already-existing session. However, get ready here to use the
+            //Owner Credential for establishing future secure sessions.
+            //
+            //For Servers based on OIC 1.1, PostOwnerAcl might fail with status
+            //OC_STACK_UNAUTHORIZED_REQ. After such a failure, OwnerAclHandler
+            //will close the current session and re-establish a new session,
+            //using the Owner Credential.
             CAEndpoint_t* endpoint = (CAEndpoint_t *)&otmCtx->selectedDeviceInfo->endpoint;
-            endpoint->port = otmCtx->selectedDeviceInfo->securePort;
-            CAResult_t caResult = CA_STATUS_OK;
-            caResult = CAcloseSslConnection(endpoint);
-
-            if(CA_STATUS_OK != caResult)
-            {
-                OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
-                SetResult(otmCtx, caResult);
-                return OC_STACK_DELETE_TRANSACTION;
-            }
 
             /**
-                * If we select NULL cipher,
-                * client will select appropriate cipher suite according to server's cipher-suite list.
-                */
-                // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
-            caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
+              * If we select NULL cipher,
+              * client will select appropriate cipher suite according to server's cipher-suite list.
+              */
+            // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
+            CAResult_t caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
             if(CA_STATUS_OK != caResult)
             {
                 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
@@ -1173,9 +1170,9 @@ static OCStackApplicationResult OwnerCredentialHandler(void *ctx, OCDoHandle UNU
             }
 
             /**
-                * in case of random PIN based OxM,
-                * revert get_psk_info callback of tinyDTLS to use owner credential.
-                */
+              * in case of random PIN based OxM,
+              * revert get_psk_info callback of tinyDTLS to use owner credential.
+              */
             if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel)
             {
                 OicUuid_t emptyUuid = { .id={0}};
@@ -1232,26 +1229,57 @@ static OCStackApplicationResult OwnerAclHandler(void *ctx, OCDoHandle UNUSED,
 
     OIC_LOG(DEBUG, TAG, "IN OwnerAclHandler");
     (void)UNUSED;
-    OCStackResult res = OC_STACK_OK;
+    OCStackResult res = clientResponse->result;
     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
     otmCtx->ocDoHandle = NULL;
+    OCProvisionDev_t* selectedDeviceInfo = otmCtx->selectedDeviceInfo;
 
-    if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+    if(OC_STACK_RESOURCE_CHANGED == res)
     {
-        if(otmCtx && otmCtx->selectedDeviceInfo)
+        if(NULL != selectedDeviceInfo)
         {
             //POST /oic/sec/doxm [{ ..., "owned":"TRUE" }]
             res = PostOwnershipInformation(otmCtx);
             if(OC_STACK_OK != res)
             {
-                OIC_LOG(ERROR, TAG, "Failed to update ownership information to new device");
+                OIC_LOG_V(ERROR, TAG, "%s: Failed to update the ownership information of the new device, res = %d",
+                    __func__, res);
+                SetResult(otmCtx, res);
+            }
+        }
+    }
+    else if((OC_STACK_UNAUTHORIZED_REQ == res) &&
+            (NULL != selectedDeviceInfo) &&
+            !selectedDeviceInfo->ownerAclUnauthorizedRequest)
+    {
+        OIC_LOG_V(WARNING, TAG, "%s: UNAUTHORIZED_REQ. Assuming server is based on OIC 1.1",
+            __func__);
+        selectedDeviceInfo->ownerAclUnauthorizedRequest = true;
+
+        //Close the temporal secure session and re-connect using the owner credential
+        CAEndpoint_t* endpoint = (CAEndpoint_t *)&selectedDeviceInfo->endpoint;
+        endpoint->port = selectedDeviceInfo->securePort;
+        CAResult_t caResult = CAcloseSslConnection(endpoint);
+
+        if(CA_STATUS_OK != caResult)
+        {
+            OIC_LOG_V(ERROR, TAG, "%s: Failed to close DTLS session, caResult = %d",
+                __func__, caResult);
+            SetResult(otmCtx, caResult);
+        }
+        else
+        {
+            res = PostOwnerAcl(otmCtx);
+            if(OC_STACK_OK != res)
+            {
+                OIC_LOG_V(ERROR, TAG, "%s: Failed to update owner ACL to new device, res = %d",
+                    __func__, res);
                 SetResult(otmCtx, res);
             }
         }
     }
     else
     {
-        res = clientResponse->result;
         OIC_LOG_V(ERROR, TAG, "OwnerAclHandler : Unexpected result %d", res);
         SetResult(otmCtx, res);
     }
index 8464364..5da4598 100644 (file)
@@ -18,6 +18,7 @@
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 #include "iotivity_config.h"
+#include "iotivity_debug.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -1001,6 +1002,30 @@ static bool ValidateOxmsel(const OicSecOxm_t *supportedMethods,
     return isValidOxmsel;
 }
 
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+static void DoxmDTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s(%p, %p)", __func__, endpoint, info);
+
+    if ((NULL != endpoint) && (NULL != info) && (CA_STATUS_OK == info->result))
+    {
+        /*
+         * Allow this OBT endpoint to bypass ACE checks for SVRs, while this
+         * device is not yet owned.
+         */
+        OC_VERIFY(CASetSecureEndpointAttribute(endpoint,
+            CA_SECURE_ENDPOINT_ATTRIBUTE_ADMINISTRATOR));
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s(%p, %p)", __func__, endpoint, info);
+}
+
+static void RegisterOTMSslHandshakeCallback(CAErrorCallback callback)
+{
+    OC_VERIFY(CA_STATUS_OK == CAregisterSslHandshakeCallback(callback));
+}
+#endif // __WITH_DTLS__ or __WITH_TLS__
+
 static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest)
 {
     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing POST request");
@@ -1068,6 +1093,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                             OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
+                            RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
                             caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, ehRequest->devAddr.adapter);
                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                             OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
@@ -1163,8 +1189,9 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                             ehRet = OC_EH_ERROR;
                             goto exit;
                         }
-                        OIC_LOG (INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+                        RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
+                        OIC_LOG(INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
                         ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
 #endif // __WITH_DTLS__ or __WITH_TLS__
                         goto exit;
@@ -1191,6 +1218,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                          * Disable anonymous ECDH cipher in tinyDTLS since device is now
                          * in owned state.
                          */
+                        RegisterOTMSslHandshakeCallback(NULL);
                         CAResult_t caRes = CA_STATUS_OK;
                         caRes = CAEnableAnonECDHCipherSuite(false);
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
@@ -1252,8 +1280,8 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                 {
                     /*
                      * If current state of the device is un-owned, enable
-                     * anonymous ECDH cipher in tinyDTLS so that Provisioning
-                     * tool can initiate JUST_WORKS ownership transfer process.
+                     * ECDHE_PSK cipher so that the Provisioning tool can
+                     * initiate the ownership transfer.
                      */
                     if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
                     {
@@ -1270,12 +1298,11 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         }
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
-                        CAResult_t caRes = CA_STATUS_OK;
-
-                        caRes = CAEnableAnonECDHCipherSuite(false);
+                        CAResult_t caRes = CAEnableAnonECDHCipherSuite(false);
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
+                        RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
                         caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256,
                                                     ehRequest->devAddr.adapter);
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
@@ -1356,6 +1383,8 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
                         OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
                         ehRet = OC_EH_ERROR;
                     }
+
+                    RegisterOTMSslHandshakeCallback(NULL);
                     CAResult_t caRes = CAEnableAnonECDHCipherSuite(false);
                     VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                     OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
@@ -1674,6 +1703,7 @@ static void PrepareMOT(const OicSecDoxm_t* doxm)
             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
             OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
 
+            RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
             caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, CA_ADAPTER_IP);
             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
 #ifdef __WITH_TLS__
index bd67af3..e217608 100644 (file)
@@ -106,19 +106,31 @@ static bool IsRequestFromDevOwner(SRMRequestContext_t *context)
         return retVal;
     }
 
-    /*
-    if(OC_STACK_OK == GetDoxmDevOwnerId(&ownerid))
-    {
-        retVal = UuidCmp(&context->subject, &ownerid);
-    }
-    */
-
-    // TODO: Added as workaround for CTT
     OicSecDoxm_t* doxm = (OicSecDoxm_t*) GetDoxmResourceData();
     if (doxm)
     {
         retVal = UuidCmp(&doxm->owner, &context->subjectUuid);
+        OIC_LOG_V(DEBUG, TAG, "%s: request was %sreceived from device owner",
+            __func__, retVal ? "" : "NOT ");
     }
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+    //Ownership Transfer sessions are allowed to bypass SVR ACEs, while this
+    //Device is not owned yet.
+    if (!retVal && (NULL != context->endPoint))
+    {
+        uint32_t allAttributes;
+        if (CAGetSecureEndpointAttributes(context->endPoint, &allAttributes) &&
+            (allAttributes & CA_SECURE_ENDPOINT_ATTRIBUTE_ADMINISTRATOR))
+        {
+            retVal = true;
+        }
+
+        OIC_LOG_V(DEBUG, TAG, "%s: request was %sreceived from Ownership Transfer session",
+            __func__, retVal ? "" : "NOT ");
+    }
+#endif
+
     return retVal;
 }