// 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
*/
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
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
#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
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
}
#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");
#ifdef MULTIPLE_OWNER
#define GetCASecureEndpointData GetCASecureEndpointDataTest
#endif
+#define SetCASecureEndpointAttribute SetCASecureEndpointAttributeTest
+#define GetCASecureEndpointAttributes GetCASecureEndpointAttributesTest
#include "../src/adapter_util/ca_adapter_net_ssl.c"
#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;
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");
}
/**
- * 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}};
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);
}
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "iotivity_config.h"
+#include "iotivity_debug.h"
#include <stdlib.h>
#include <string.h>
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");
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");
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;
* 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);
{
/*
* 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)
{
}
#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);
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");
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__
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;
}