// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include "iotivity_config.h"
#include <stdlib.h>
#include <string.h>
-#if HAVE_STRINGS_H
+#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
-#ifdef __WITH_DTLS__
-#include "global.h"
-#endif
-
#include "ocstack.h"
#include "oic_malloc.h"
#include "payload_logging.h"
#include "utlist.h"
#include "ocrandom.h"
#include "ocpayload.h"
+#include "ocpayloadcbor.h"
#include "cainterface.h"
#include "ocserverrequest.h"
#include "resourcemanager.h"
#include "credresource.h"
#include "srmutility.h"
#include "pinoxmcommon.h"
+#include "oxmverifycommon.h"
+#include "octhread.h"
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#include "pkix_interface.h"
+#include "ca_adapter_net_ssl.h"
+#endif
-#define TAG "SRM-DOXM"
+#define TAG "OIC_SRM_DOXM"
+#define CHAR_ZERO ('0')
/** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
* The value of payload size is increased until reaching belox max cbor size. */
/** Max cbor size payload. */
static const uint16_t CBOR_MAX_SIZE = 4400;
-/** DOXM Map size - Number of mandatory items. */
-static const uint8_t DOXM_MAP_SIZE = 7;
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+/** MAX uuid seed size */
+#define MAX_UUID_SEED_SIZE (64)
+/** MIN uuid seed size */
+#define MIN_UUID_SEED_SIZE (8)
+
+/** Buffer to save the seed of device UUID */
+static uint8_t gUuidSeed[MAX_UUID_SEED_SIZE];
+static size_t gUuidSeedSize = 0;
+#endif
+
+#ifdef MULTIPLE_OWNER
+#define MAX_SUBOWNER_SIZE (64)
+#define MIN_SUBOWNER_SIZE (1)
+#define DEFAULT_SUBOWNER_SIZE (32)
+
+static size_t gMaxSubOwnerSize = DEFAULT_SUBOWNER_SIZE;
+#endif
+
+typedef enum ConfirmState{
+ CONFIRM_STATE_READY = 0,
+ CONFIRM_STATE_WAIT = 1,
+ CONFIRM_STATE_ACCEPTED = 2,
+ CONFIRM_STATE_DENIED = 3
+}ConfirmState_t;
static OicSecDoxm_t *gDoxm = NULL;
+static oc_mutex g_mutexDoxm = NULL;
+static bool g_isDoxmNull = false;
static OCResourceHandle gDoxmHandle = NULL;
static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS;
{.id = {0}}, /* OicUuid_t deviceID */
false, /* bool dpc */
{.id = {0}}, /* OicUuid_t owner */
+#ifdef MULTIPLE_OWNER
+ NULL, /* OicSecSubOwner_t sub-owner list */
+ NULL, /* OicSecMomType_t multiple owner mode */
+#endif //MULTIPLE_OWNER
{.id = {0}}, /* OicUuid_t rownerID */
};
+static uint16_t gConfirmMsgId = 0;
+static ConfirmState_t gConfirmState = CONFIRM_STATE_READY;
+
+static uint8_t gEmptyUuid[UUID_LENGTH] = {0};
+
+/**
+ * This method is internal method.
+ * the param roParsed is optionally used to know whether cborPayload has
+ * at least read only property value or not.
+ */
+static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t size,
+ OicSecDoxm_t **doxm, bool *roParsed);
+
void DeleteDoxmBinData(OicSecDoxm_t* doxm)
{
if (doxm)
//clean oxm
OICFree(doxm->oxm);
+#ifdef MULTIPLE_OWNER
+ //clean mom
+ OICFree(doxm->mom);
+
+ //clean sub-owner list
+ if(NULL != doxm->subOwners)
+ {
+ OicSecSubOwner_t* subowner = NULL;
+ OicSecSubOwner_t* temp = NULL;
+ LL_FOREACH_SAFE(doxm->subOwners, subowner, temp)
+ {
+ LL_DELETE(doxm->subOwners, subowner);
+ OICFree(subowner);
+ }
+ }
+#endif //MULTIPLE_OWNER
+
//Clean doxm itself
OICFree(doxm);
}
+
+ if(g_mutexDoxm)
+ {
+ oc_mutex_free(g_mutexDoxm);
+ g_mutexDoxm = NULL;
+ }
}
-OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, size_t *size)
+OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, size_t *size,
+ bool rwOnly)
{
if (NULL == doxm || NULL == payload || NULL != *payload || NULL == size)
{
char* strUuid = NULL;
int64_t cborEncoderResult = CborNoError;
- uint8_t mapSize = DOXM_MAP_SIZE;
- if (doxm->oxmTypeLen > 0)
- {
- mapSize++;
- }
- if (doxm->oxmLen > 0)
- {
- mapSize++;
- }
uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
VERIFY_NON_NULL(TAG, outPayload, ERROR);
cbor_encoder_init(&encoder, outPayload, cborLen, 0);
- cborEncoderResult = cbor_encoder_create_map(&encoder, &doxmMap, mapSize);
+ cborEncoderResult = cbor_encoder_create_map(&encoder, &doxmMap, CborIndefiniteLength);
VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Map.");
//OxmType -- Not Mandatory
}
//Oxm -- Not Mandatory
- if (doxm->oxmLen > 0)
+ if (doxm->oxmLen > 0 && false == rwOnly)
{
CborEncoder oxm;
cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXMS_NAME,
VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Value.");
//sct -- Mandatory
- cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUPPORTED_CRED_TYPE_NAME,
- strlen(OIC_JSON_SUPPORTED_CRED_TYPE_NAME));
- VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Tag");
- cborEncoderResult = cbor_encode_int(&doxmMap, doxm->sct);
- VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Value.");
+ if (false == rwOnly)
+ {
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUPPORTED_CRED_TYPE_NAME,
+ strlen(OIC_JSON_SUPPORTED_CRED_TYPE_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Tag");
+ cborEncoderResult = cbor_encode_int(&doxmMap, doxm->sct);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Value.");
+ }
//Owned -- Mandatory
cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OWNED_NAME,
cborEncoderResult = cbor_encode_boolean(&doxmMap, doxm->owned);
VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Value.");
- //DeviceId -- Mandatory
- cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVICE_ID_NAME,
- strlen(OIC_JSON_DEVICE_ID_NAME));
- VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
- ret = ConvertUuidToStr(&doxm->deviceID, &strUuid);
- VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
- cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
- VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
- OICFree(strUuid);
- strUuid = NULL;
+ if (false == rwOnly)
+ {
+ //DeviceId -- Mandatory
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVICE_ID_NAME,
+ strlen(OIC_JSON_DEVICE_ID_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
+ ret = ConvertUuidToStr(&doxm->deviceID, &strUuid);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
+ OICFree(strUuid);
+ strUuid = NULL;
+ }
+
+#ifdef MULTIPLE_OWNER
+ //Device SubOwnerID -- Not Mandatory
+ if(doxm->subOwners)
+ {
+ size_t subOwnerLen = 0;
+ OicSecSubOwner_t* subOwner = NULL;
+ LL_FOREACH(doxm->subOwners, subOwner)
+ {
+ subOwnerLen++;
+ }
+
+ CborEncoder subOwners;
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUBOWNERID_NAME,
+ strlen(OIC_JSON_SUBOWNERID_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwnerId Tag.");
+ cborEncoderResult = cbor_encoder_create_array(&doxmMap, &subOwners, subOwnerLen);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwner Array.");
+
+ subOwner = NULL;
+ LL_FOREACH(doxm->subOwners, subOwner)
+ {
+ char* strUuid = NULL;
+ ret = ConvertUuidToStr(&subOwner->uuid, &strUuid);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+ cborEncoderResult = cbor_encode_text_string(&subOwners, strUuid, strlen(strUuid));
+ OICFree(strUuid);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwnerId Value");
+ }
+ cborEncoderResult = cbor_encoder_close_container(&doxmMap, &subOwners);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing SubOwnerId.");
+ }
+
+ //Multiple Owner Mode -- Not Mandatory
+ if(doxm->mom)
+ {
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_MOM_NAME,
+ strlen(OIC_JSON_MOM_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Tag");
+ cborEncoderResult = cbor_encode_int(&doxmMap, (int64_t)doxm->mom->mode);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Value.");
+ }
+#endif //MULTIPLE_OWNER
//devownerid -- Mandatory
cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVOWNERID_NAME,
OICFree(strUuid);
strUuid = NULL;
- //DPC -- Mandatory
- cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DPC_NAME,
- strlen(OIC_JSON_DPC_NAME));
- VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Tag.");
- cborEncoderResult = cbor_encode_boolean(&doxmMap, doxm->dpc);
- VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Value.");
+ //RT -- Mandatory
+ CborEncoder rtArray;
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_RT_NAME,
+ strlen(OIC_JSON_RT_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
+ cborEncoderResult = cbor_encoder_create_array(&doxmMap, &rtArray, 1);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
+ for (size_t i = 0; i < 1; i++)
+ {
+ cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_DOXM,
+ strlen(OIC_RSRC_TYPE_SEC_DOXM));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
+ }
+ cborEncoderResult = cbor_encoder_close_container(&doxmMap, &rtArray);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
+
+ //IF-- Mandatory
+ CborEncoder ifArray;
+ cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_IF_NAME,
+ strlen(OIC_JSON_IF_NAME));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
+ cborEncoderResult = cbor_encoder_create_array(&doxmMap, &ifArray, 1);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
+ for (size_t i = 0; i < 1; i++)
+ {
+ cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
+ strlen(OC_RSRVD_INTERFACE_DEFAULT));
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
+ }
+ cborEncoderResult = cbor_encoder_close_container(&doxmMap, &ifArray);
+ VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
cborEncoderResult = cbor_encoder_close_container(&encoder, &doxmMap);
VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing DoxmMap.");
if (CborNoError == cborEncoderResult)
{
- *size = encoder.ptr - outPayload;
+ *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
*payload = outPayload;
ret = OC_STACK_OK;
}
OIC_LOG(DEBUG, TAG, "Memory getting reallocated.");
// reallocate and try again!
OICFree(outPayload);
+ outPayload = NULL;
// Since the allocated initial memory failed, double the memory.
- cborLen += encoder.ptr - encoder.end;
+ cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
OIC_LOG_V(DEBUG, TAG, "Doxm reallocation size : %zd.", cborLen);
cborEncoderResult = CborNoError;
- ret = DoxmToCBORPayload(doxm, payload, &cborLen);
+ ret = DoxmToCBORPayload(doxm, payload, &cborLen, rwOnly);
*size = cborLen;
}
OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size,
OicSecDoxm_t **secDoxm)
{
+ return CBORPayloadToDoxmBin(cborPayload, size, secDoxm, NULL);
+}
+
+static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t size,
+ OicSecDoxm_t **secDoxm, bool *roParsed)
+{
if (NULL == cborPayload || NULL == secDoxm || NULL != *secDoxm || 0 == size)
{
return OC_STACK_INVALID_PARAM;
CborValue oxmType;
cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmTypeLen);
- VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.")
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.");
VERIFY_SUCCESS(TAG, doxm->oxmTypeLen != 0, ERROR);
doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(*doxm->oxmType));
int i = 0;
size_t len = 0;
- while (cbor_value_is_valid(&oxmType))
+ while (cbor_value_is_valid(&oxmType) && cbor_value_is_text_string(&oxmType))
{
cborFindResult = cbor_value_dup_text_string(&oxmType, &doxm->oxmType[i++],
&len, NULL);
- VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.")
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.");
cborFindResult = cbor_value_advance(&oxmType);
- VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.")
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.");
}
}
{
CborValue oxm;
cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmLen);
- VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.")
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.");
VERIFY_SUCCESS(TAG, doxm->oxmLen != 0, ERROR);
doxm->oxm = (OicSecOxm_t *)OICCalloc(doxm->oxmLen, sizeof(*doxm->oxm));
VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmName Array.")
int i = 0;
- while (cbor_value_is_valid(&oxm))
+ while (cbor_value_is_valid(&oxm) && cbor_value_is_integer(&oxm))
{
- cborFindResult = cbor_value_get_int(&oxm, (int *) &doxm->oxm[i++]);
+ int tmp;
+
+ cborFindResult = cbor_value_get_int(&oxm, &tmp);
VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName Value")
+ doxm->oxm[i++] = (OicSecOxm_t)tmp;
cborFindResult = cbor_value_advance(&oxm);
VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmName.")
}
+
+ if (roParsed)
+ {
+ *roParsed = true;
+ }
+ }
+ else
+ {
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+ doxm->oxm = (OicSecOxm_t *) OICCalloc(gDoxm->oxmLen, sizeof(*doxm->oxm));
+ VERIFY_NON_NULL(TAG, doxm->oxm, ERROR);
+ doxm->oxmLen = gDoxm->oxmLen;
+ for (size_t i = 0; i < gDoxm->oxmLen; i++)
+ {
+ doxm->oxm[i] = gDoxm->oxm[i];
+ }
}
cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_SEL_NAME, &doxmMap);
if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
{
- cborFindResult = cbor_value_get_int(&doxmMap, (int *) &doxm->oxmSel);
+ int oxmSel;
+
+ cborFindResult = cbor_value_get_int(&doxmMap, &oxmSel);
VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sel Name Value.")
+ doxm->oxmSel = (OicSecOxm_t)oxmSel;
}
else // PUT/POST JSON may not have oxmsel so set it to the gDoxm->oxmSel
{
cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUPPORTED_CRED_TYPE_NAME, &doxmMap);
if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
{
- cborFindResult = cbor_value_get_int(&doxmMap, (int *) &doxm->sct);
+ int sct;
+
+ cborFindResult = cbor_value_get_int(&doxmMap, &sct);
VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sct Name Value.")
+ doxm->sct = (OicSecCredType_t)sct;
+
+ if (roParsed)
+ {
+ *roParsed = true;
+ }
}
else // PUT/POST JSON may not have sct so set it to the gDoxm->sct
{
doxm->owned = gDoxm->owned;
}
- cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DPC_NAME, &doxmMap);
- if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
- {
- cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->dpc);
- VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding DPC Value.")
- }
- else // PUT/POST JSON may not have owned so set it to the gDomx->owned
- {
- VERIFY_NON_NULL(TAG, gDoxm, ERROR);
- doxm->owned = false;
- }
-
cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVICE_ID_NAME, &doxmMap);
if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
{
OICFree(strUuid);
strUuid = NULL;
}
+ else
+ {
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+ memcpy(doxm->deviceID.id, &gDoxm->deviceID.id, sizeof(doxm->deviceID.id));
+ }
cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVOWNERID_NAME, &doxmMap);
if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
OICFree(strUuid);
strUuid = NULL;
}
+ else
+ {
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+ memcpy(doxm->owner.id, gDoxm->owner.id, sizeof(doxm->owner.id));
+ }
+
+#ifdef MULTIPLE_OWNER
+ cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_MOM_NAME, &doxmMap);
+ if(CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
+ {
+ int mode = 0;
+ cborFindResult = cbor_value_get_int(&doxmMap, &mode);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding mom Name Value.")
+ if(NULL == doxm->mom)
+ {
+ doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+ VERIFY_NON_NULL(TAG, doxm->mom, ERROR);
+ }
+ doxm->mom->mode = (OicSecMomType_t)mode;
+ }
+ else if(NULL != gDoxm && NULL != gDoxm->mom)
+ {
+ // PUT/POST JSON may not have 'mom' so set it to the gDomx->mom
+ if(NULL == doxm->mom)
+ {
+ doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+ VERIFY_NON_NULL(TAG, doxm->mom, ERROR);
+ }
+ doxm->mom->mode = gDoxm->mom->mode;
+ }
+
+ cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUBOWNERID_NAME, &doxmMap);
+ if(CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
+ {
+ size_t subOwnerLen = 0;
+ CborValue subOwnerCbor;
+ cborFindResult = cbor_value_get_array_length(&doxmMap, &subOwnerLen);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubOwner array Length.");
+ VERIFY_SUCCESS(TAG, 0 != subOwnerLen, ERROR);
+
+ cborFindResult = cbor_value_enter_container(&doxmMap, &subOwnerCbor);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering SubOwner Array.")
+
+ while (cbor_value_is_valid(&subOwnerCbor) && cbor_value_is_text_string(&subOwnerCbor))
+ {
+ OCStackResult convertRes = OC_STACK_ERROR;
+ OicSecSubOwner_t* subOwner = NULL;
+ char* strUuid = NULL;
+ size_t uuidLen = 0;
+
+ cborFindResult = cbor_value_dup_text_string(&subOwnerCbor, &strUuid, &uuidLen, NULL);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubOwnerId Value");
+
+ subOwner = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+ VERIFY_NON_NULL(TAG, subOwner, ERROR);
+
+ convertRes = ConvertStrToUuid(strUuid, &subOwner->uuid);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == convertRes, ERROR);
+ subOwner->status = MOT_STATUS_DONE;
+ LL_APPEND(doxm->subOwners, subOwner);
+
+ cborFindResult = cbor_value_advance(&subOwnerCbor);
+ VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing SubOwnerId.")
+ }
+ }
+ else if(NULL != gDoxm && NULL != gDoxm->subOwners)
+ {
+ // PUT/POST JSON may not have 'subOwners' so set it to the gDomx->subOwners
+ OicSecSubOwner_t* subOwnerItor = NULL;
+ LL_FOREACH(gDoxm->subOwners, subOwnerItor)
+ {
+ OicSecSubOwner_t* subOwnerId = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+ VERIFY_NON_NULL(TAG, subOwnerId, ERROR);
+
+ memcpy(&subOwnerId->uuid, &subOwnerItor->uuid, sizeof(OicUuid_t));
+ subOwnerId->status = MOT_STATUS_DONE;
+
+ LL_APPEND(doxm->subOwners, subOwnerId);
+ }
+ }
+#endif //MULTIPLE_OWNER
cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_ROWNERID_NAME, &doxmMap);
if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
OICFree(strUuid);
strUuid = NULL;
}
+ else
+ {
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+ memcpy(doxm->rownerID.id, gDoxm->rownerID.id, sizeof(doxm->rownerID.id));
+ }
*secDoxm = doxm;
ret = OC_STACK_OK;
// Convert Doxm data into CBOR for update to persistent storage
uint8_t *payload = NULL;
size_t size = 0;
- OCStackResult res = DoxmToCBORPayload(doxm, &payload, &size);
+ OCStackResult res = DoxmToCBORPayload(doxm, &payload, &size, false);
if (payload && (OC_STACK_OK == res)
&& (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, payload, size)))
{
bool bOwnedMatch = false; // does 'owned' query value matches with doxm.owned status?
bool bDeviceIDQry = false; // does querystring contains 'deviceid' query ?
bool bDeviceIDMatch = false; // does 'deviceid' query matches with doxm.deviceid ?
+ bool bInterfaceQry = false; // does querystring contains 'if' query ?
+ bool bInterfaceMatch = false; // does 'if' query matches with oic.if.baseline ?
+#ifdef MULTIPLE_OWNER
+ bool bMotMatch = false; // does 'mom' query value is not '0' && does query value matches with doxm.owned status?
+#endif //MULTIPLE_OWNER
OicParseQueryIter_t parseIter = {.attrPos = NULL};
}
}
+#ifdef MULTIPLE_OWNER
+ if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_MOM_NAME, strlen(OIC_JSON_MOM_NAME)) == 0)
+ {
+ OicSecMomType_t momMode = (OicSecMomType_t)(parseIter.valPos[0] - CHAR_ZERO);
+ if(NULL != gDoxm->mom && momMode != gDoxm->mom->mode)
+ {
+ if(GetNextQuery(&parseIter))
+ {
+ if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
+ {
+ if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
+ (gDoxm->owned))
+ {
+ bMotMatch = true;
+ }
+ }
+ }
+ }
+ return bMotMatch;
+ }
+#endif //MULTIPLE_OWNER
+
if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
{
bDeviceIDQry = true;
bDeviceIDMatch = true;
}
}
+
+ if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
+ {
+ bInterfaceQry = true;
+ if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
+ {
+ bInterfaceMatch = true;
+ }
+ return (bInterfaceQry ? bInterfaceMatch: true);
+ }
}
- return ((bOwnedQry ? bOwnedMatch : true) && (bDeviceIDQry ? bDeviceIDMatch : true));
+ return ((bOwnedQry ? bOwnedMatch : true) &&
+ (bDeviceIDQry ? bDeviceIDMatch : true));
}
static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
//Checking if Get request is a query.
if (ehRequest->query)
{
+ OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
OIC_LOG(DEBUG, TAG, "HandleDoxmGetRequest processing query");
if (!ValidateQuery(ehRequest->query))
{
if (ehRet == OC_EH_OK)
{
- if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size))
+ if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size, false))
{
- payload = NULL;
+ OIC_LOG(WARNING, TAG, "DoxmToCBORPayload failed in HandleDoxmGetRequest");
}
}
+ OIC_LOG(DEBUG, TAG, "Send payload for doxm GET request");
+ OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
+
// Send response payload to request originator
- if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, payload, size))
- {
- ehRet = OC_EH_ERROR;
- OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandleDoxmGetRequest");
- }
+ ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
+ OC_EH_OK : OC_EH_ERROR;
OICFree(payload);
return ehRet;
}
-static OCEntityHandlerResult HandleDoxmPutRequest(const OCEntityHandlerRequest * ehRequest)
+static void updateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst)
{
- OIC_LOG (DEBUG, TAG, "Doxm EntityHandle processing PUT request");
- OCEntityHandlerResult ehRet = OC_EH_ERROR;
- OicUuid_t emptyOwner = {.id = {0} };
+ if(src && dst)
+ {
+ // update oxmsel
+ dst->oxmSel = src->oxmSel;
- /*
- * Convert CBOR Doxm data into binary. This will also validate
- * the Doxm data received.
- */
- OicSecDoxm_t *newDoxm = NULL;
+ //update owner
+ memcpy(&(dst->owner), &(src->owner), sizeof(OicUuid_t));
- if (ehRequest->payload)
+ //update rowner
+ memcpy(&(dst->rownerID), &(src->rownerID), sizeof(OicUuid_t));
+
+ //update deviceuuid
+ memcpy(&(dst->deviceID), &(src->deviceID), sizeof(OicUuid_t));
+
+ //Update owned status
+ if(dst->owned != src->owned)
+ {
+ dst->owned = src->owned;
+ }
+
+#ifdef MULTIPLE_OWNER
+ if(src->mom)
+ {
+ OIC_LOG(DEBUG, TAG, "dectected 'mom' property");
+ if(NULL == dst->mom)
+ {
+ dst->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+ if(NULL != dst->mom)
+ {
+ dst->mom->mode = src->mom->mode;
+ }
+ }
+ }
+#endif //MULTIPLE_OWNER
+ }
+}
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#ifdef MULTIPLE_OWNER
+/**
+ * Internal function to get number of sub-owner
+ */
+static size_t GetSubOwnerSize()
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+ size_t numberOfSubOwner = 0;
+
+ if (gDoxm && gDoxm->subOwners)
{
- uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
- size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
- OCStackResult res = CBORPayloadToDoxm(payload, size, &newDoxm);
+ OicSecSubOwner_t* subowner = NULL;
+ LL_FOREACH(gDoxm->subOwners, subowner)
+ {
+ numberOfSubOwner++;
+ }
+ }
- if (newDoxm && OC_STACK_OK == res)
+ OIC_LOG_V(DEBUG, TAG, "Numer of registered sub-owner=%d", numberOfSubOwner);
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+
+ return numberOfSubOwner;
+}
+
+/**
+ * Callback function to handle MOT DTLS handshake result.
+ * @param[out] endpoint remote device information.
+ * @param[out] errorInfo CA Error information.
+ */
+void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *endpoint,
+ const CAErrorInfo_t *errorInfo)
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+ if (!endpoint || !errorInfo)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid param");
+ return;
+ }
+
+ if (!gDoxm)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s: gDoxm is NULL", __func__);
+ return;
+ }
+
+ if ((CA_STATUS_OK == errorInfo->result) && (true == gDoxm->owned)
+ && (OIC_PRECONFIG_PIN == gDoxm->oxmSel) && (NULL != gDoxm->mom)
+ && (OIC_MULTIPLE_OWNER_DISABLE != gDoxm->mom->mode) && (CA_ADAPTER_TCP != endpoint->adapter))
+ {
+ OIC_LOG_V(INFO, TAG, "DTLS session established for sub-owner authentication : (%s:%d)",
+ endpoint->addr, endpoint->port);
+
+ const CASecureEndpoint_t* authenticatedSubOwnerInfo = CAGetSecureEndpointData(endpoint);
+ if (authenticatedSubOwnerInfo)
{
- if (OIC_JUST_WORKS == newDoxm->oxmSel)
+ if (0 == memcmp(authenticatedSubOwnerInfo->identity.id, gDoxm->owner.id,
+ authenticatedSubOwnerInfo->identity.id_length))
+ {
+ OIC_LOG(WARNING, TAG, "Super owner tried MOT, this request will be ignored.");
+ return;
+ }
+
+ OicSecSubOwner_t* subOwnerInst = NULL;
+ LL_FOREACH(gDoxm->subOwners, subOwnerInst)
{
- if ((false == gDoxm->owned) && (false == newDoxm->owned))
+ if(0 == memcmp(subOwnerInst->uuid.id,
+ authenticatedSubOwnerInfo->identity.id,
+ authenticatedSubOwnerInfo->identity.id_length))
{
- /*
- * 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.
- */
- if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ break;
+ }
+ }
+
+ if (NULL == subOwnerInst)
+ {
+ subOwnerInst = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+ if (subOwnerInst)
+ {
+ char* strUuid = NULL;
+ if (OC_STACK_OK != ConvertUuidToStr(&subOwnerInst->uuid, &strUuid))
{
- OIC_LOG (INFO, TAG, "Doxm EntityHandle enabling AnonECDHCipherSuite");
-#ifdef __WITH_DTLS__
- ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
-#endif //__WITH_DTLS__
- goto exit;
+ OIC_LOG(WARNING, TAG, "ConvertUuidToStr error");
+ }
+ OIC_LOG_V(DEBUG, TAG, "Adding New SubOwner(%s)", strUuid);
+
+ if (gMaxSubOwnerSize > GetSubOwnerSize())
+ {
+ memcpy(subOwnerInst->uuid.id, authenticatedSubOwnerInfo->identity.id,
+ authenticatedSubOwnerInfo->identity.id_length);
+ LL_APPEND(gDoxm->subOwners, subOwnerInst);
+ if (!UpdatePersistentStorage(gDoxm))
+ {
+ OIC_LOG(ERROR, TAG, "Failed to register SubOwner UUID into Doxm");
+ }
}
else
{
-#ifdef __WITH_DTLS__
- //Save the owner's UUID to derive owner credential
- memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+ OIC_LOG_V(ERROR, TAG, "Number of sub-owner exceeded : (MAX SIZE=%d)", gMaxSubOwnerSize);
- // Update new state in persistent storage
- if (true == UpdatePersistentStorage(gDoxm))
+ //Close DTLS session
+ if (CA_STATUS_OK != CAcloseSslSession(endpoint))
{
- ehRet = OC_EH_OK;
+ OIC_LOG_V(ERROR, TAG, "CAcloseSslSession error for [%s:%d]", endpoint->addr, endpoint->port);
}
- else
+
+ //Remove credential
+ if (OC_STACK_RESOURCE_DELETED != RemoveCredential(&subOwnerInst->uuid))
{
- OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
- ehRet = OC_EH_ERROR;
+ OIC_LOG_V(ERROR, TAG, "RemoveCredential error for [%s]", strUuid);
}
- /*
- * Disable anonymous ECDH cipher in tinyDTLS since device is now
- * in owned state.
- */
- CAResult_t caRes = CA_STATUS_OK;
- caRes = CAEnableAnonECDHCipherSuite(false);
- VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
- OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
-
-#ifdef __WITH_X509__
-#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE
- CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
-#endif //__WITH_X509__
-#endif //__WITH_DTLS__
+ // TODO: How to send error to client side?
}
+
+ OICFree(strUuid);
}
}
- else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
- {
- if ((false == gDoxm->owned) && (false == newDoxm->owned))
- {
- /*
- * 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.
- */
- if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
- {
- gDoxm->oxmSel = newDoxm->oxmSel;
- //Update new state in persistent storage
- if ((UpdatePersistentStorage(gDoxm) == true))
- {
- ehRet = OC_EH_OK;
- }
- else
- {
- OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
- ehRet = OC_EH_ERROR;
- }
+ }
+ }
-#ifdef __WITH_DTLS__
- CAResult_t caRes = CA_STATUS_OK;
+ if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
+ {
+ OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler");
+ }
- caRes = CAEnableAnonECDHCipherSuite(false);
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+}
+#endif //MULTIPLE_OWNER
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+/**
+ * Function to validate oxmsel with oxms.
+ *
+ * @param[in] supportedMethods Array of supported methods
+ * @param[in] numberOfMethods number of supported methods
+ * @param[out] selectedMethod Selected methods
+ * @return TRUE on success
+ */
+static bool ValidateOxmsel(const OicSecOxm_t *supportedMethods,
+ size_t numberOfMethods, OicSecOxm_t *selectedMethod)
+{
+ bool isValidOxmsel = false;
+
+ OIC_LOG(DEBUG, TAG, "IN ValidateOxmsel");
+ if (numberOfMethods == 0 || !supportedMethods)
+ {
+ OIC_LOG(WARNING, TAG, "Could not find a supported OxM.");
+ return isValidOxmsel;
+ }
+
+ for (size_t i = 0; i < numberOfMethods; i++)
+ {
+ if (*selectedMethod == supportedMethods[i])
+ {
+ isValidOxmsel = true;
+ break;
+ }
+ }
+ if (!isValidOxmsel)
+ {
+ OIC_LOG(ERROR, TAG, "Not allowed Oxmsel.");
+ return isValidOxmsel;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT ValidateOxmsel");
+
+ return isValidOxmsel;
+}
+
+static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest)
+{
+ OIC_LOG (DEBUG, TAG, "Doxm EntityHandle processing POST request");
+ OCEntityHandlerResult ehRet = OC_EH_ERROR;
+ OicUuid_t emptyOwner = {.id = {0} };
+ static uint16_t previousMsgId = 0;
+ bool isDuplicatedMsg = false;
+
+ /*
+ * Convert CBOR Doxm data into binary. This will also validate
+ * the Doxm data received.
+ */
+ OicSecDoxm_t *newDoxm = NULL;
+
+ if (ehRequest->payload)
+ {
+ uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
+ size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
+ bool roParsed = false;
+ OCStackResult res = CBORPayloadToDoxmBin(payload, size, &newDoxm, &roParsed);
+ if (newDoxm && OC_STACK_OK == res)
+ {
+ /*
+ * message ID is supported for CoAP over UDP only according to RFC 7252
+ * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
+ * In case of other transport adapter, duplicate message check is not required.
+ */
+ if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
+ previousMsgId == ehRequest->messageID)
+ {
+ isDuplicatedMsg = true;
+ }
+
+ if (isDuplicatedMsg && ehRequest->messageID == gConfirmMsgId)
+ {
+ if (CONFIRM_STATE_WAIT == gConfirmState)
+ {
+ OIC_LOG(DEBUG, TAG, "Confirm callback already invoked.");
+ OIC_LOG(DEBUG, TAG, "This request will be ignored.");
+ DeleteDoxmBinData(newDoxm);
+ return OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG_V(DEBUG, TAG, "Confirm request already done, Confirm Result = %s", (CONFIRM_STATE_ACCEPTED == gConfirmState ? "ACCEPTED" : "DENIED"));
+ ehRet = (CONFIRM_STATE_ACCEPTED == gConfirmState ? OC_EH_OK : OC_EH_NOT_ACCEPTABLE);
+ goto exit;
+ }
+ }
+
+ // Check request on RO property
+ if (true == roParsed)
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only propertys");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ goto exit;
+ }
+
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+
+ // in owned state
+ if (true == gDoxm->owned)
+ {
+ if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ goto exit;
+ }
+ //Update gDoxm based on newDoxm
+ updateWriteableProperty(newDoxm, gDoxm);
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#ifdef MULTIPLE_OWNER
+ //handle mom
+ if(gDoxm->mom)
+ {
+ if(OIC_MULTIPLE_OWNER_DISABLE != gDoxm->mom->mode)
+ {
+ CAResult_t caRes = CA_STATUS_FAILED;
+ if(OIC_PRECONFIG_PIN == gDoxm->oxmSel || OIC_RANDOM_DEVICE_PIN == gDoxm->oxmSel)
+ {
+ caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, ehRequest->devAddr.adapter);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
+
+ //Set the device id to derive temporal PSK
+ SetUuidForPinBasedOxm(&gDoxm->deviceID);
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
+ }
+
+ CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
+ }
+ else
+ {
+ //if MOM is disabled, revert the DTLS handshake callback
+ if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL))
+ {
+ OIC_LOG(WARNING, TAG, "Error while revert the DTLS Handshake Callback.");
+ }
+ }
+ }
+
+ if(newDoxm->subOwners)
+ {
+ OicSecSubOwner_t* subowner = NULL;
+ OicSecSubOwner_t* temp = NULL;
+
+ OIC_LOG(DEBUG, TAG, "dectected 'subowners' property");
+
+ if(gDoxm->subOwners)
+ {
+ LL_FOREACH_SAFE(gDoxm->subOwners, subowner, temp)
+ {
+ LL_DELETE(gDoxm->subOwners, subowner);
+ OICFree(subowner);
+ }
+ }
+
+ subowner = NULL;
+ temp = NULL;
+ LL_FOREACH_SAFE(newDoxm->subOwners, subowner, temp)
+ {
+ LL_DELETE(newDoxm->subOwners, subowner);
+ LL_APPEND(gDoxm->subOwners, subowner);
+ }
+ }
+#endif //MULTIPLE_OWNER
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+ //Update new state in persistent storage
+ if (UpdatePersistentStorage(gDoxm) == true)
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ }
+ goto exit;
+ }
+
+ // in unowned state
+ if ((false == gDoxm->owned) && (false == newDoxm->owned))
+ {
+ if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ goto exit;
+ }
+
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+ if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ {
+ InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+ NULL, OIC_OTM_STARTED);
+ }
+ else
+ {
+ OIC_LOG_V(INFO, TAG, "%s: request owner not empty",__func__);
+ char* strUuid = NULL;
+ if (OC_STACK_OK == ConvertUuidToStr(&newDoxm->owner, &strUuid))
+ {
+ OIC_LOG_V(INFO, TAG, "%s: request owner: %s",__func__, strUuid);
+ OICFree(strUuid);
+ }
+ }
+#endif
+
+ if (OIC_JUST_WORKS == newDoxm->oxmSel || OIC_MV_JUST_WORKS == newDoxm->oxmSel)
+ {
+ /*
+ * 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.
+ */
+ if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ {
+ gDoxm->oxmSel = newDoxm->oxmSel;
+ //Update new state in persistent storage
+ if ((UpdatePersistentStorage(gDoxm) == true))
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+ }
+ OIC_LOG (INFO, TAG, "Doxm EntityHandle enabling AnonECDHCipherSuite");
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ goto exit;
+ }
+ else
+ {
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ //Save the owner's UUID to derive owner credential
+ memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+
+ // Update new state in persistent storage
+ if (true == UpdatePersistentStorage(gDoxm))
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+ }
+
+ /*
+ * Disable anonymous ECDH cipher in tinyDTLS since device is now
+ * in owned state.
+ */
+ CAResult_t caRes = CA_STATUS_OK;
+ caRes = CAEnableAnonECDHCipherSuite(false);
VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
- caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);
- VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ //In case of Mutual Verified Just-Works, verify mutualVerifNum
+ if (OIC_MV_JUST_WORKS == newDoxm->oxmSel && false == newDoxm->owned &&
+ false == isDuplicatedMsg)
+ {
+ uint8_t preMutualVerifNum[OWNER_PSK_LENGTH_128] = {0};
+ uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN] = {0};
+ OicUuid_t deviceID = {.id = {0}};
+
+ //Generate mutualVerifNum
+ OCServerRequest * request = GetServerRequestUsingHandle(ehRequest->requestHandle);
+
+ char label[LABEL_LEN] = {0};
+ snprintf(label, LABEL_LEN, "%s%s", MUTUAL_VERIF_NUM, OXM_MV_JUST_WORKS);
+ if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))
+ {
+ OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+
+ }
+
+ CAResult_t pskRet = CAGenerateOwnerPSK((CAEndpoint_t *)&request->devAddr,
+ (uint8_t *)label,
+ strlen(label),
+ gDoxm->owner.id, sizeof(gDoxm->owner.id),
+ gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id),
+ preMutualVerifNum, OWNER_PSK_LENGTH_128);
+ if (CA_STATUS_OK != pskRet)
+ {
+ OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+
+ }
+
+ memcpy(mutualVerifNum, preMutualVerifNum + OWNER_PSK_LENGTH_128 - sizeof(mutualVerifNum),
+ sizeof(mutualVerifNum));
+
+ gConfirmMsgId = ehRequest->messageID;
+ gConfirmState = CONFIRM_STATE_WAIT;
+ //Wait for user confirmation
+ if (OC_STACK_OK != VerifyOwnershipTransfer(mutualVerifNum, DISPLAY_NUM | USER_CONFIRM))
+ {
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ gConfirmState = CONFIRM_STATE_DENIED;
+ }
+ else
+ {
+ ehRet = OC_EH_OK;
+ gConfirmState = CONFIRM_STATE_ACCEPTED;
+ }
+ }
- char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,};
- if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ }
+ }
+ else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
+ {
+ /*
+ * 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.
+ */
+ if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ {
+ gDoxm->oxmSel = newDoxm->oxmSel;
+ //Update new state in persistent storage
+ if ((UpdatePersistentStorage(gDoxm) == true))
{
- //Set the device id to derive temporal PSK
- SetUuidForRandomPinOxm(&gDoxm->deviceID);
-
- /**
- * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
- * Credential should not be saved into SVR.
- * For this reason, use a temporary get_psk_info callback to random PIN OxM.
- */
- caRes = CARegisterDTLSCredentialsHandler(GetDtlsPskForRandomPinOxm);
- VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
ehRet = OC_EH_OK;
}
else
{
- OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
+ OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
ehRet = OC_EH_ERROR;
}
-#endif //__WITH_DTLS__
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ CAResult_t caRes = CA_STATUS_OK;
+
+ caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ caRes = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ ehRequest->devAddr.adapter);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+
+ if (!isDuplicatedMsg)
+ {
+ char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
+ if (OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
+ {
+ //Set the device id to derive temporal PSK
+ SetUuidForPinBasedOxm(&gDoxm->deviceID);
+
+ /**
+ * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
+ * Credential should not be saved into SVR.
+ * For this reason, use a temporary get_psk_info callback to random PIN OxM.
+ */
+ caRes = CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
+ ehRet = OC_EH_ERROR;
+ }
+ }
+#endif // __WITH_DTLS__ or __WITH_TLS__
}
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
else
{
-#ifdef __WITH_DTLS__
//Save the owner's UUID to derive owner credential
memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+ // In case of random-pin based OTM, close the PIN display if callback is registered.
+ if (!isDuplicatedMsg)
+ {
+ ClosePinDisplay();
+ }
+
//Update new state in persistent storage
if (UpdatePersistentStorage(gDoxm) == true)
{
OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
ehRet = OC_EH_ERROR;
}
-#endif
}
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ }
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+ else if (OIC_MANUFACTURER_CERTIFICATE == newDoxm->oxmSel || OIC_CON_MFG_CERT == newDoxm->oxmSel)
+ {
+ //Get user confirmation
+ if (false == newDoxm->owned &&
+ false == isDuplicatedMsg &&
+ memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)
+ {
+ gConfirmMsgId = ehRequest->messageID;
+ gConfirmState = CONFIRM_STATE_WAIT;
+ if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM))
+ {
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ gConfirmState = CONFIRM_STATE_DENIED;
+ goto exit;
+ }
+ else
+ {
+ ehRet = OC_EH_OK;
+ gConfirmState = CONFIRM_STATE_ACCEPTED;
+ }
+ }
+
+ //Save the owner's UUID to derive owner credential
+ memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+ gDoxm->oxmSel = newDoxm->oxmSel;
+ //Update new state in persistent storage
+ if (UpdatePersistentStorage(gDoxm))
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ }
+ CAResult_t caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ //Unset pre-selected ciphersuite, if any
+ caRes = CASelectCipherSuite(0, ehRequest->devAddr.adapter);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(DEBUG, TAG, "No ciphersuite preferred");
+
+ VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterPkixInfoHandler(GetManufacturerPkixInfo), ERROR);
+ VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterGetCredentialTypesHandler(InitManufacturerCipherSuiteList), ERROR);
}
+#endif // __WITH_DTLS__ or __WITH_TLS__
}
/*
ehRet = OC_EH_ERROR;
goto exit;
}
- ownerRes = SetDpairingRownerId(&gDoxm->owner);
- if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
- {
- ehRet = OC_EH_ERROR;
- goto exit;
- }
- ownerRes = SetPconfRownerId(&gDoxm->owner);
- if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
- {
- ehRet = OC_EH_ERROR;
- goto exit;
- }
gDoxm->owned = true;
memcpy(&gDoxm->rownerID, &gDoxm->owner, sizeof(OicUuid_t));
// Update new state in persistent storage
if (UpdatePersistentStorage(gDoxm))
{
- //Update default ACL of security resource to prevent anonymous user access.
- if(OC_STACK_OK == UpdateDefaultSecProvACL())
+ //Update default ACE of security resource to prevent anonymous user access.
+ if(OC_STACK_OK == UpdateDefaultSecProvACE())
{
ehRet = OC_EH_OK;
}
}
else
{
- OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
- ehRet = OC_EH_ERROR;
+ OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ }
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+ if (OIC_MANUFACTURER_CERTIFICATE == gDoxm->oxmSel ||
+ OIC_CON_MFG_CERT== gDoxm->oxmSel)
+ {
+ CAregisterPkixInfoHandler(GetPkixInfo);
+ CAregisterGetCredentialTypesHandler(InitCipherSuiteList);
+ }
+
+ InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+ &gDoxm->owner, OIC_OTM_DONE);
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ }
+ }
+ }
+
+exit:
+ if(OC_EH_OK != ehRet)
+ {
+ /*
+ * If some error is occured while ownership transfer,
+ * ownership transfer related resource should be revert back to initial status.
+ */
+ if(gDoxm)
+ {
+ if(!gDoxm->owned)
+ {
+ OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
+
+ if (!isDuplicatedMsg)
+ {
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+ InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+ NULL, OIC_OTM_ERROR);
+#endif
+ RestoreDoxmToInitState();
+ RestorePstatToInitState();
+ OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
+ }
+ }
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
+ }
+ }
+
+ previousMsgId = ehRequest->messageID;
+
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+ CAEndpoint_t peer = {0};
+ OCDevAddr devAddr = ehRequest->devAddr;
+
+ memcpy(&peer.addr, &devAddr.addr, sizeof(peer.addr));
+ peer.port = devAddr.port;
+ peer.adapter = (CATransportAdapter_t)devAddr.adapter;
+
+ if ((devAddr.flags & OC_FLAG_SECURE) && (false == CAIsExistSslPeer(&peer)))
+ {
+ OIC_LOG_V(WARNING, TAG, "Not Exist Peer");
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ //Send payload to request originator
+ ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+ OC_EH_OK : OC_EH_ERROR;
+ }
+#else
+ //Send payload to request originator
+ ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+ OC_EH_OK : OC_EH_ERROR;
+#endif
+
+ DeleteDoxmBinData(newDoxm);
+
+ return ehRet;
+}
+
+#ifdef MULTIPLE_OWNER
+static OCEntityHandlerResult HandleDoxmDeleteRequest(const OCEntityHandlerRequest *ehRequest)
+{
+ OIC_LOG(DEBUG, TAG, "Processing DoxmDeleteRequest");
+
+ OCEntityHandlerResult ehRet = OC_EH_BAD_REQ;
+
+ if (NULL == ehRequest->query)
+ {
+ return ehRet;
+ }
+
+ OicParseQueryIter_t parseIter = { .attrPos=NULL };
+ OicUuid_t subject = {.id={0}};
+
+ //Parsing REST query to get the subject
+ ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
+ while (GetNextQuery(&parseIter))
+ {
+ if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBOWNERID_NAME,
+ parseIter.attrLen) == 0)
+ {
+ if (0 == strncmp((const char*)parseIter.valPos, WILDCARD_RESOURCE_URI,
+ strlen(WILDCARD_RESOURCE_URI)))
+ {
+ if(OC_STACK_RESOURCE_DELETED == RemoveSubOwner(&WILDCARD_SUBJECT_ID))
+ {
+ ehRet = OC_EH_RESOURCE_DELETED;
+ }
+ }
+ else
+ {
+ OCStackResult ret = ConvertStrToUuid((const char*)parseIter.valPos, &subject);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+ if(OC_STACK_RESOURCE_DELETED == RemoveSubOwner(&subject))
+ {
+ ehRet = OC_EH_RESOURCE_DELETED;
}
}
}
}
-exit:
- if(OC_EH_OK != ehRet)
- {
- OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request,"\
- "DOXM will be reverted.");
-
- /*
- * If some error is occured while ownership transfer,
- * ownership transfer related resource should be revert back to initial status.
- */
- RestoreDoxmToInitState();
- RestorePstatToInitState();
- }
-
- //Send payload to request originator
- if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
- {
- ehRet = OC_EH_ERROR;
- OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandleDoxmPostRequest");
- }
- DeleteDoxmBinData(newDoxm);
+ //Send response to request originator
+ ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+ OC_EH_OK : OC_EH_ERROR;
return ehRet;
+exit:
+ return OC_EH_ERROR;
}
+#endif //MULTIPLE_OWNER
OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
OCEntityHandlerRequest * ehRequest,
return ehRet;
}
+ oc_mutex_lock(g_mutexDoxm);
+
+ if(g_isDoxmNull)
+ {
+ oc_mutex_unlock(g_mutexDoxm);
+ return OC_EH_SERVICE_UNAVAILABLE;
+ }
+
if (flag & OC_REQUEST_FLAG)
{
OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
ehRet = HandleDoxmGetRequest(ehRequest);
break;
- case OC_REST_PUT:
- ehRet = HandleDoxmPutRequest(ehRequest);
+ case OC_REST_POST:
+ ehRet = HandleDoxmPostRequest(ehRequest);
+ break;
+
+#ifdef MULTIPLE_OWNER
+ case OC_REST_DELETE:
+ ehRet = HandleDoxmDeleteRequest(ehRequest);
break;
+#endif //MULTIPLE_OWNER
default:
- ehRet = OC_EH_ERROR;
- SendSRMResponse(ehRequest, ehRet, NULL, 0);
+ ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+ OC_EH_OK : OC_EH_ERROR;
break;
}
+
+ oc_mutex_unlock(g_mutexDoxm);
}
return ehRet;
{
OCStackResult ret = OCCreateResource(&gDoxmHandle,
OIC_RSRC_TYPE_SEC_DOXM,
- OIC_MI_DEF,
+ OC_RSRVD_INTERFACE_DEFAULT,
OIC_RSRC_DOXM_URI,
DoxmEntityHandler,
NULL,
- OC_OBSERVABLE | OC_SECURE |
- OC_EXPLICIT_DISCOVERABLE);
+ OC_SECURE |
+ OC_DISCOVERABLE);
if (OC_STACK_OK != ret)
{
*/
static OCStackResult CheckDeviceID()
{
+ OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
+
OCStackResult ret = OC_STACK_ERROR;
bool validId = false;
+
+ if (!gDoxm)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s: gDoxm is NULL", __func__);
+ return OC_STACK_INVALID_PARAM;
+ }
+
for (uint8_t i = 0; i < UUID_LENGTH; i++)
{
if (gDoxm->deviceID.id[i] != 0)
if (!validId)
{
- if (OCGenerateUuid(gDoxm->deviceID.id) != RAND_UUID_OK)
+ char* strUuid = NULL;
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+ //If seed value is exist, generate UUID using seed with SHA256
+ if (0 != gUuidSeedSize)
+ {
+ uint8_t hashVal[MBEDTLS_MD_MAX_SIZE] = {0};
+ mbedtls_md_context_t sha_ctx;
+ int mbedret = 1;
+
+ OIC_LOG(DEBUG, TAG, "UUID will be generated using seed w/ SHA256");
+ OIC_LOG(DEBUG, TAG, "Seed value : ");
+ OIC_LOG_BUFFER(DEBUG, TAG, gUuidSeed, gUuidSeedSize);
+
+ mbedtls_md_init( &sha_ctx );
+ mbedret = mbedtls_md_setup( &sha_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 1 );
+ if (0 == mbedret)
+ {
+ mbedtls_md_starts( &sha_ctx );
+ mbedtls_md_update( &sha_ctx, gUuidSeed, gUuidSeedSize);
+ mbedtls_md_finish(&sha_ctx, (unsigned char*)hashVal);
+ memcpy(gDoxm->deviceID.id, hashVal, sizeof(gDoxm->deviceID.id));
+ ret = OC_STACK_OK;
+ }
+ else
+ {
+ OIC_LOG_V(ERROR, TAG, "mbedtls_md_setup() returned -0x%04x\n", -mbedret);
+ ret = OC_STACK_ERROR;
+ }
+ mbedtls_md_free( &sha_ctx );
+ }
+ else
+ {
+ if (RAND_UUID_OK != OCGenerateUuid(gDoxm->deviceID.id))
+ {
+ OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
+ return OC_STACK_ERROR;
+ }
+ ret = OC_STACK_OK;
+ }
+#else
+ if (RAND_UUID_OK != OCGenerateUuid(gDoxm->deviceID.id))
{
OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
return ret;
}
ret = OC_STACK_OK;
+#endif
+
+ if (OC_STACK_OK == ConvertUuidToStr(&gDoxm->deviceID, &strUuid))
+ {
+ OIC_LOG_V(DEBUG, TAG, "Generated device UUID is [%s]", strUuid);
+ OICFree(strUuid);
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Failed to convert UUID to string");
+ }
+
if (!UpdatePersistentStorage(gDoxm))
{
{
ret = OC_STACK_OK;
}
+
+ OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
+
return ret;
}
return gDoxm;
}
+#if defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
+/**
+ * Internal API to prepare MOT
+ */
+static void PrepareMOT(const OicSecDoxm_t* doxm)
+{
+ OIC_LOG(INFO, TAG, "IN PrepareMOT");
+ VERIFY_NON_NULL(TAG, doxm, ERROR);
+
+ if(true == doxm->owned && NULL != doxm->mom && OIC_MULTIPLE_OWNER_DISABLE != doxm->mom->mode)
+ {
+ CAResult_t caRes = CA_STATUS_FAILED;
+
+ OIC_LOG(INFO, TAG, "Multiple Ownership Transfer Enabled!");
+
+ if(OIC_PRECONFIG_PIN == doxm->oxmSel)
+ {
+ caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CA_ADAPTER_IP);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+#ifdef __WITH_TLS__
+ caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CA_ADAPTER_TCP);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+#endif
+ OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
+
+ //Set the device id to derive temporal PSK
+ SetUuidForPinBasedOxm(&doxm->deviceID);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
+ return;
+ }
+
+ CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
+ }
+
+ OIC_LOG(INFO, TAG, "OUT PrepareMOT");
+ return;
+exit:
+ OIC_LOG(WARNING, TAG, "Error in PrepareMOT");
+}
+#endif //defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
+
OCStackResult InitDoxmResource()
{
OCStackResult ret = OC_STACK_ERROR;
+ if (!g_mutexDoxm)
+ {
+ g_mutexDoxm = oc_mutex_new();
+ if(!g_mutexDoxm)
+ {
+ return OC_STACK_ERROR;
+ }
+ }
+
+ gConfirmState = CONFIRM_STATE_READY;
+ gConfirmMsgId = 0;
+
//Read DOXM resource from PS
uint8_t *data = NULL;
size_t size = 0;
gDoxm = GetDoxmDefault();
}
+ oc_mutex_lock(g_mutexDoxm);
+ g_isDoxmNull = false;
+ oc_mutex_unlock(g_mutexDoxm);
+
//In case of the server is shut down unintentionally, we should initialize the owner
- if(false == gDoxm->owned)
+ if(gDoxm && (false == gDoxm->owned))
{
OicUuid_t emptyUuid = {.id={0}};
memcpy(&gDoxm->owner, &emptyUuid, sizeof(OicUuid_t));
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+ InvokeOtmEventHandler(NULL, 0, NULL, OIC_OTM_READY);
+#endif
}
ret = CheckDeviceID();
OIC_LOG (ERROR, TAG, "CheckDeviceID failed");
}
OICFree(data);
+
+#if defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
+ //if MOT is enabled, MOT should be prepared.
+ if(gDoxm && gDoxm->owned)
+ {
+ PrepareMOT(gDoxm);
+ }
+#endif // defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
+
return ret;
}
OCStackResult DeInitDoxmResource()
{
+ oc_mutex_lock(g_mutexDoxm);
OCStackResult ret = OCDeleteResource(gDoxmHandle);
if (gDoxm != &gDefaultDoxm)
{
DeleteDoxmBinData(gDoxm);
}
gDoxm = NULL;
+ g_isDoxmNull = true;
if (OC_STACK_OK == ret)
{
+ oc_mutex_unlock(g_mutexDoxm);
return OC_STACK_OK;
}
else
{
+ oc_mutex_unlock(g_mutexDoxm);
return OC_STACK_ERROR;
}
}
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)
+{
+ OIC_LOG_V(INFO, TAG, "In %s", __func__);
+
+ if (NULL == seed)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+ if (MAX_UUID_SEED_SIZE < seedSize)
+ {
+ OIC_LOG_V(ERROR, TAG, "Seed size is too long (MAX size is %d bytes)", MAX_UUID_SEED_SIZE);
+ return OC_STACK_INVALID_PARAM;
+ }
+ if (MIN_UUID_SEED_SIZE > seedSize)
+ {
+ OIC_LOG_V(ERROR, TAG, "Seed size is too small (MIN size is %d bytes)", MIN_UUID_SEED_SIZE);
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ memset(gUuidSeed, 0x00, sizeof(gUuidSeed));
+ memcpy(gUuidSeed, seed, seedSize);
+ gUuidSeedSize = seedSize;
+
+ OIC_LOG_V(INFO, TAG, "Out %s", __func__);
+
+ return OC_STACK_OK;
+}
+
+#endif
+
+OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
+{
+ bool isOwnerUpdated = false;
+ bool isRownerUpdated = false;
+ if (NULL == deviceID)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+ if (NULL == gDoxm)
+ {
+ OIC_LOG(ERROR, TAG, "Doxm resource is not initialized.");
+ return OC_STACK_NO_RESOURCE;
+ }
+
+#ifdef __WITH_DTLS__
+ //for normal device.
+ if (true == gDoxm->owned
+ && memcmp(gEmptyUuid, gDoxm->owner.id, sizeof(gDoxm->owner.id)) != 0
+ && memcmp(gDoxm->deviceID.id, gDoxm->owner.id, sizeof(gDoxm->owner.id)) != 0)
+ {
+ OIC_LOG(ERROR, TAG, "This device owned by owner's device.");
+ OIC_LOG(ERROR, TAG, "Device UUID cannot be changed to guarantee the reliability of the connection.");
+ return OC_STACK_ERROR;
+ }
+#endif //__WITH_DTLS
+
+ //Save the previous UUID
+ OicUuid_t prevUuid;
+ memcpy(prevUuid.id, gDoxm->deviceID.id, sizeof(prevUuid.id));
+
+ //Change the device UUID
+ memcpy(gDoxm->deviceID.id, deviceID->id, sizeof(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));
+ isOwnerUpdated = true;
+ }
+ //Change the resource owner ID if necessary
+ if (memcmp(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id)) == 0)
+ {
+ memcpy(gDoxm->rownerID.id, deviceID->id, sizeof(deviceID->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));
+ if (isOwnerUpdated)
+ {
+ memcpy(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id));
+ }
+ if (isRownerUpdated)
+ {
+ memcpy(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.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;
+ }
+ return OC_STACK_OK;
+}
+
OCStackResult GetDoxmDevOwnerId(OicUuid_t *devownerid)
{
OCStackResult retVal = OC_STACK_ERROR;
return retVal;
}
+#ifdef MULTIPLE_OWNER
+/**
+ * Compare the UUID to SubOwner.
+ *
+ * @param[in] uuid device UUID
+ *
+ * @return true if context->subjectId exist subowner list, else false.
+ */
+bool IsSubOwner(const OicUuid_t* uuid)
+{
+ bool retVal = false;
+
+ if (NULL == uuid)
+ {
+ return retVal;
+ }
+
+ if (gDoxm && gDoxm->subOwners)
+ {
+ if (memcmp(gDoxm->owner.id, uuid->id, sizeof(gDoxm->owner.id)) == 0)
+ {
+ return false;
+ }
+
+ OicSecSubOwner_t* subOwner = NULL;
+ LL_FOREACH(gDoxm->subOwners, subOwner)
+ {
+ if (memcmp(subOwner->uuid.id, uuid->id, sizeof(uuid->id)) == 0)
+ {
+ return true;
+ }
+ }
+ }
+ return retVal;
+}
+#endif //MULTIPLE_OWNER
+
+OCStackResult SetMOTStatus(bool enable)
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+#ifdef MULTIPLE_OWNER
+ OCStackResult ret = OC_STACK_NO_MEMORY;
+ uint8_t *cborPayload = NULL;
+ size_t size = 0;
+ bool isDeallocateRequired = false;
+
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+
+ if (NULL == gDoxm->mom && !enable)
+ {
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return OC_STACK_OK;
+ }
+
+ if (NULL == gDoxm->mom)
+ {
+ gDoxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+ VERIFY_NON_NULL(TAG, gDoxm->mom, ERROR);
+ isDeallocateRequired = true;
+ }
+
+ gDoxm->mom->mode = (enable ? OIC_MULTIPLE_OWNER_ENABLE : OIC_MULTIPLE_OWNER_DISABLE);
+ gDoxm->oxmSel = OIC_PRECONFIG_PIN;
+
+ ret = DoxmToCBORPayload(gDoxm, &cborPayload, &size, false);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+ ret = UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, cborPayload, size);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+ isDeallocateRequired = false;
+
+exit:
+ if (isDeallocateRequired)
+ {
+ OICFree(gDoxm->mom);
+ }
+ if (cborPayload)
+ {
+ OICFree(cborPayload);
+ }
+ OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, ret);
+ return ret;
+#else
+ OC_UNUSED(enable);
+ OIC_LOG(DEBUG, TAG, "Multiple Owner is not enabled.");
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return OC_STACK_ERROR;
+#endif //MULTIPLE_OWNER
+}
+
+OCStackResult RemoveSubOwner(const OicUuid_t* subOwner)
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+#ifdef MULTIPLE_OWNER
+ OCStackResult ret = OC_STACK_ERROR;
+ bool isDeleted = false;
+
+ if (NULL == subOwner)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid sub owner UUID.");
+ return OC_STACK_INVALID_PARAM;
+ }
+ if (NULL == gDoxm)
+ {
+ OIC_LOG(ERROR, TAG, "Doxm resource is NULL");
+ return OC_STACK_NO_RESOURCE;
+ }
+ if ( NULL == gDoxm->subOwners)
+ {
+ OIC_LOG(WARNING, TAG, "Sub Owner list is empty.");
+ return OC_STACK_ERROR;
+ }
+
+ OicSecSubOwner_t* curSubOwner = NULL;
+ OicSecSubOwner_t* tempSubOwner = NULL;
+ LL_FOREACH_SAFE(gDoxm->subOwners, curSubOwner, tempSubOwner)
+ {
+ if (memcmp(curSubOwner->uuid.id, subOwner->id, sizeof(subOwner->id)) == 0 ||
+ memcmp(WILDCARD_SUBJECT_ID.id, subOwner->id, sizeof(OicUuid_t)) == 0)
+ {
+ char* strUuid = NULL;
+ ret = ConvertUuidToStr(&curSubOwner->uuid, &strUuid);
+ if (OC_STACK_OK != ret)
+ {
+ OIC_LOG_V(ERROR, TAG, "ConvertUuidToStr error : %d", ret);
+ break;
+ }
+
+ OIC_LOG_V(INFO, TAG, "[%s] will be removed from sub owner list.", strUuid);
+ LL_DELETE(gDoxm->subOwners, curSubOwner);
+
+ //Remove the cred for sub owner
+ ret = RemoveCredential(&curSubOwner->uuid);
+ if (OC_STACK_RESOURCE_DELETED != ret)
+ {
+ OIC_LOG_V(WARNING, TAG, "RemoveCredential error for [%s] : %d", strUuid, ret);
+ break;
+ }
+
+ // TODO: Remove the ACL for sub owner (Currently ACL is not required for sub-owner)
+
+ OICFree(strUuid);
+
+ isDeleted = true;
+ }
+ }
+
+ if (isDeleted)
+ {
+ //Update persistent storage
+ if (UpdatePersistentStorage(gDoxm))
+ {
+ ret = OC_STACK_RESOURCE_DELETED;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "UpdatePersistentStorage error");
+ ret = OC_STACK_ERROR;
+ }
+ }
+
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return ret;
+#else
+ OC_UNUSED(subOwner);
+ OIC_LOG(DEBUG, TAG, "Multiple Owner is not enabled.");
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return OC_STACK_ERROR;
+#endif //MULTIPLE_OWNER
+
+}
+
+OCStackResult SetNumberOfSubOwner(size_t numOfSubOwner)
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+#ifdef MULTIPLE_OWNER
+ if (MAX_SUBOWNER_SIZE < numOfSubOwner || MIN_SUBOWNER_SIZE > numOfSubOwner)
+ {
+ OIC_LOG_V(ERROR, TAG, "Invalid number of sub owner : %d", numOfSubOwner);
+ return OC_STACK_INVALID_PARAM;
+ }
+ gMaxSubOwnerSize = numOfSubOwner;
+ OIC_LOG_V(DEBUG, TAG, "Number of SubOwner = %d", gMaxSubOwnerSize);
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return OC_STACK_OK;
+#else
+ OC_UNUSED(numOfSubOwner);
+ OIC_LOG(DEBUG, TAG, "Multiple Owner is not enabled.");
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ return OC_STACK_ERROR;
+#endif //MULTIPLE_OWNER
+}
+
/**
* Function to restore doxm resurce to initial status.
* This function will use in case of error while ownership transfer
*/
void RestoreDoxmToInitState()
{
+
+ gConfirmState = CONFIRM_STATE_READY;
+ gConfirmMsgId = 0;
+
if(gDoxm)
{
OIC_LOG(INFO, TAG, "DOXM resource will revert back to initial status.");
}
}
}
+
+OCStackResult SetDoxmSelfOwnership(const OicUuid_t* newROwner)
+{
+ OCStackResult ret = OC_STACK_ERROR;
+ uint8_t *cborPayload = NULL;
+ size_t size = 0;
+
+ if(NULL == gDoxm)
+ {
+ ret = OC_STACK_NO_RESOURCE;
+ return ret;
+ }
+
+ if( newROwner && (false == gDoxm->owned) )
+ {
+ gDoxm->owned = true;
+ memcpy(gDoxm->owner.id, newROwner->id, sizeof(newROwner->id));
+ memcpy(gDoxm->rownerID.id, newROwner->id, sizeof(newROwner->id));
+
+ ret = DoxmToCBORPayload(gDoxm, &cborPayload, &size, false);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+ ret = UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, cborPayload, size);
+ VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+ OICFree(cborPayload);
+ }
+
+ return ret;
+
+exit:
+ OICFree(cborPayload);
+ return ret;
+}
+