Commit bfbff11f authored by Dan Mihai's avatar Dan Mihai Committed by Kevin Kane

[IOT-1801] Implement OCF Security CR1339

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: default avatarDan Mihai <Daniel.Mihai@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17279Reviewed-by: default avatarKevin Kane <kkane@microsoft.com>
Tested-by: default avatarjenkins-iotivity <jenkins@iotivity.org>
parent 90f761c9
......@@ -324,8 +324,16 @@ 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.
*/
......
......@@ -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
......
......@@ -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
......
......@@ -938,6 +938,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.
*
......@@ -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
......
......@@ -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");
......
......@@ -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"
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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__
......
......@@ -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;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment