X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fsecurity%2Fsrc%2Fdoxmresource.c;h=e88a381f693edf78ef0d391e82517f11f254a37c;hb=refs%2Fchanges%2F27%2F209927%2F1;hp=aa05845c6b577e66cabc012498a5d4aa03263c54;hpb=4e551fc3ea3ed5ef6267c6f185b9c0ad817b037c;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/security/src/doxmresource.c b/resource/csdk/security/src/doxmresource.c index aa05845..e88a381 100644 --- a/resource/csdk/security/src/doxmresource.c +++ b/resource/csdk/security/src/doxmresource.c @@ -17,23 +17,21 @@ // limitations under the License. // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +#include "iotivity_config.h" #include #include -#if HAVE_STRINGS_H +#ifdef HAVE_STRINGS_H #include #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" @@ -49,8 +47,18 @@ #include "credresource.h" #include "srmutility.h" #include "pinoxmcommon.h" +#include "oxmverifycommon.h" +#include "octhread.h" +#include "oic_time.h" +#include "oic_string.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. */ @@ -59,11 +67,41 @@ static const uint16_t CBOR_SIZE = 512; /** 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 = 9; +#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 oc_mutex g_mutexWait; +static oc_thread g_waitConfirmThreadId; +oc_cond g_condWait; +static InformOxmSelectedCallback_t g_InformOxmSelectedCallback = NULL; +static bool g_isConfirmResult; static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS; static OicSecDoxm_t gDefaultDoxm = @@ -78,9 +116,26 @@ static OicSecDoxm_t gDefaultDoxm = {.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) @@ -95,12 +150,36 @@ void DeleteDoxmBinData(OicSecDoxm_t* 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) { @@ -121,21 +200,12 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz 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 @@ -159,7 +229,7 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz } //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, @@ -185,11 +255,14 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz 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, @@ -198,16 +271,62 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz 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, @@ -231,13 +350,6 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz OICFree(strUuid); strUuid = NULL; - //x.com.samsung.dpc -- not Mandatory(vendor-specific), but this type is boolean, so instance always has a value. - 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, @@ -275,7 +387,7 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz if (CborNoError == cborEncoderResult) { - *size = encoder.ptr - outPayload; + *size = cbor_encoder_get_buffer_size(&encoder, outPayload); *payload = outPayload; ret = OC_STACK_OK; } @@ -285,11 +397,12 @@ exit: 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; } @@ -308,6 +421,12 @@ exit: 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; @@ -334,7 +453,7 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, 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)); @@ -349,9 +468,9 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, { 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."); } } @@ -361,7 +480,7 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, { 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)); @@ -373,18 +492,40 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, int i = 0; 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 { @@ -395,8 +536,16 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, 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 { @@ -416,18 +565,6 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, 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 dpc so set it to the gDomx->dpc - { - VERIFY_NON_NULL(TAG, gDoxm, ERROR); - doxm->dpc = gDoxm->dpc; - } - cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVICE_ID_NAME, &doxmMap); if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap)) { @@ -438,6 +575,11 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, 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)) @@ -449,6 +591,87 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, 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)) @@ -460,6 +683,11 @@ OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size, 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; @@ -489,7 +717,7 @@ static bool UpdatePersistentStorage(OicSecDoxm_t * doxm) // 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))) { @@ -530,6 +758,9 @@ static bool ValidateQuery(const char * 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}; @@ -552,6 +783,28 @@ static bool ValidateQuery(const char * query) } } +#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; @@ -575,7 +828,8 @@ static bool ValidateQuery(const char * query) } } - return ((bOwnedQry ? bOwnedMatch : true) && (bDeviceIDQry ? bDeviceIDMatch : true)); + return ((bOwnedQry ? bOwnedMatch : true) && + (bDeviceIDQry ? bDeviceIDMatch : true)); } static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest) @@ -606,7 +860,7 @@ static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest if (ehRet == OC_EH_OK) { - if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size)) + if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size, false)) { OIC_LOG(WARNING, TAG, "DoxmToCBORPayload failed in HandleDoxmGetRequest"); } @@ -616,136 +870,722 @@ static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest 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 HandleDoxmPostRequest(const OCEntityHandlerRequest * ehRequest) +static void updateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst) { - OIC_LOG (DEBUG, TAG, "Doxm EntityHandle processing POST request"); - OCEntityHandlerResult ehRet = OC_EH_ERROR; - OicUuid_t emptyOwner = {.id = {0} }; - static uint16_t previousMsgId = 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=%zd", 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=%zd)", 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); - VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR); - OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED"); + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); +} +#endif //MULTIPLE_OWNER +#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__) - caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256); - VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR); +/** + * 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; - if(previousMsgId != ehRequest->messageID) - { - char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,}; - if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1)) + 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; +} + +void SetInformOxmSelCB(InformOxmSelectedCallback_t informOxmSelCB) +{ + OIC_LOG_V(DEBUG, TAG, "In %s", __func__); + g_InformOxmSelectedCallback = informOxmSelCB; + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); +} + +void UnsetInformOxmSelCB() +{ + OIC_LOG_V(DEBUG, TAG, "In %s", __func__); + g_InformOxmSelectedCallback = NULL; + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); +} + +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) +static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest); + +static void DestroyEntityHandlerRequest(OCEntityHandlerRequest * ehRequest) +{ + if (ehRequest == NULL) { + OIC_LOG(WARNING, TAG, "ehRequest is NULL"); + return; + } + + OICFree(ehRequest->query); + + if (ehRequest->payload) { + OICFree(((OCSecurityPayload *)ehRequest->payload)->securityData); + OICFree(ehRequest->payload); + } + + OICFree(ehRequest); +} + +void * WaitConfirm(OCEntityHandlerRequest * ehRequest) +{ + bool confirmResult = false, confirmState = false; + + oc_mutex_lock(g_mutexWait); + oc_cond_wait(g_condWait, g_mutexWait); + oc_cond_free(g_condWait); + g_condWait = NULL; + + oc_mutex_unlock(g_mutexWait); + oc_mutex_free(g_mutexWait); + g_mutexWait = NULL; + + g_isConfirmResult = true; + GetAsyncVerifyUserResult(&confirmResult, &confirmState); + if (confirmResult == true) + { + gConfirmState = CONFIRM_STATE_ACCEPTED; + HandleDoxmPostRequest(ehRequest); + g_isConfirmResult = false; + return NULL; + } + else + { + gConfirmState = CONFIRM_STATE_DENIED; + HandleDoxmPostRequest(ehRequest); + g_isConfirmResult = false; + return NULL; + } + + DestroyEntityHandlerRequest(ehRequest); + + return NULL; +} + +static OCEntityHandlerRequest *CopyRequest(OCEntityHandlerRequest *entityHandlerRequest) +{ + OIC_LOG(INFO, TAG, "Copying received request for slow response"); + + if (!entityHandlerRequest) + { + OIC_LOG_V(ERROR, TAG, "%s: entityHandlerRequest is NULL", __func__); + return NULL; + } + + OCEntityHandlerRequest *copyOfRequest = + (OCEntityHandlerRequest *)OICCalloc(1, sizeof(OCEntityHandlerRequest)); + if(!copyOfRequest) + { + OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure"); + return NULL; + } + + memcpy(copyOfRequest, entityHandlerRequest, sizeof(OCEntityHandlerRequest)); + + if (entityHandlerRequest->query) + { + copyOfRequest->query = OICStrdup(entityHandlerRequest->query); + if(!copyOfRequest->query) + { + OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure"); + OICFree(copyOfRequest); + return NULL; + } + } + + if (entityHandlerRequest->payload) + { + copyOfRequest->payload = + (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!copyOfRequest->payload) + { + OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure"); + OICFree(copyOfRequest->query); + OICFree(copyOfRequest); + return NULL; + } + + if (((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize) + { + ((OCSecurityPayload *)copyOfRequest->payload)->securityData = + (uint8_t *)OICCalloc(1, ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize); + if(!((OCSecurityPayload *)copyOfRequest->payload)->securityData) + { + OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure"); + OICFree(copyOfRequest->payload); + OICFree(copyOfRequest->query); + OICFree(copyOfRequest); + return NULL; + } + + memcpy(((OCSecurityPayload *)copyOfRequest->payload)->securityData, + ((OCSecurityPayload *)entityHandlerRequest->payload)->securityData, + ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize); + + ((OCSecurityPayload *)(copyOfRequest->payload))->payloadSize = + ((OCSecurityPayload *)(entityHandlerRequest->payload))->payloadSize; + } + + copyOfRequest->payload->type = entityHandlerRequest->payload->type; + copyOfRequest->messageID = entityHandlerRequest->messageID; + } + + // Ignore vendor specific header options for example + copyOfRequest->numRcvdVendorSpecificHeaderOptions = 0; + copyOfRequest->rcvdVendorSpecificHeaderOptions = NULL; + + if (copyOfRequest) + { + OIC_LOG(INFO, TAG, "Copied client request"); + } + else + { + OIC_LOG(ERROR, TAG, "Error copying client request"); + } + return copyOfRequest; +} +#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__) + +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 && g_isConfirmResult == false) + { + 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; + } + + if(0 != memcmp(&gDoxm->owner.id, &newDoxm->owner.id, sizeof(gDoxm->owner.id))) + { + OIC_LOG(ERROR, TAG, "Not acceptable request for owned property"); + ehRet = OC_EH_NOT_ACCEPTABLE; + } + + //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 (g_InformOxmSelectedCallback) + { + g_InformOxmSelectedCallback(newDoxm->oxmSel); + } + +#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"); + + //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; + } + } + +#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)) + { + ehRet = OC_EH_OK; + } + else + { + OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage"); + ehRet = OC_EH_ERROR; + } + +#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 - SetUuidForRandomPinOxm(&gDoxm->deviceID); + 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 = CARegisterDTLSCredentialsHandler(GetDtlsPskForRandomPinOxm); + caRes = CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm); VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR); ehRet = OC_EH_OK; } @@ -755,14 +1595,20 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest ehRet = OC_EH_ERROR; } } -#endif //__WITH_DTLS__ +#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) { @@ -773,9 +1619,81 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest 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) + { + if (CONFIRM_STATE_ACCEPTED != gConfirmState && CONFIRM_STATE_DENIED != gConfirmState) + { + //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 != VerifyUserConfirm()) + { + if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM)) + { + ehRet = OC_EH_NOT_ACCEPTABLE; + gConfirmState = CONFIRM_STATE_DENIED; + goto exit; + } + } + else + { + OCEntityHandlerRequest * ehRequestCopy = CopyRequest(ehRequest); + VERIFY_NON_NULL(TAG, ehRequestCopy, ERROR); + + g_condWait = oc_cond_new(); + g_mutexWait = oc_mutex_new(); + if (oc_thread_new (&g_waitConfirmThreadId, WaitConfirm, ehRequestCopy)) + { + oc_thread_detach(g_waitConfirmThreadId); + } + + previousMsgId = ehRequest->messageID; + + return OC_EH_SLOW; + } + } + } + else if (CONFIRM_STATE_DENIED == gConfirmState) + { + ehRet = OC_EH_NOT_ACCEPTABLE; + goto exit; + } + + //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__ } /* @@ -811,18 +1729,6 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest 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)); @@ -846,6 +1752,17 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest 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__ } } } @@ -853,41 +1770,118 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest 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 && previousMsgId != ehRequest->messageID) + 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 { - OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request,"\ - "DOXM will be reverted."); - RestoreDoxmToInitState(); - RestorePstatToInitState(); + 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; + } } } - else - { - OIC_LOG(ERROR, TAG, "Invalid DOXM resource."); - } - } - else - { - previousMsgId = ehRequest->messageID; } - //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, @@ -901,6 +1895,14 @@ OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag, 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"); @@ -915,11 +1917,19 @@ OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag, 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; @@ -951,8 +1961,17 @@ OCStackResult CreateDoxmResource() */ 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) @@ -964,12 +1983,64 @@ static OCStackResult CheckDeviceID() 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)) { @@ -981,6 +2052,9 @@ static OCStackResult CheckDeviceID() { ret = OC_STACK_OK; } + + OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__); + return ret; } @@ -1000,10 +2074,70 @@ const OicSecDoxm_t* GetDoxmResourceData() 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; @@ -1028,11 +2162,18 @@ OCStackResult InitDoxmResource() 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(); @@ -1047,24 +2188,37 @@ OCStackResult InitDoxmResource() 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; } } @@ -1079,6 +2233,115 @@ OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID) 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; @@ -1109,12 +2372,210 @@ OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid) 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 : %zd", numOfSubOwner); + return OC_STACK_INVALID_PARAM; + } + gMaxSubOwnerSize = numOfSubOwner; + OIC_LOG_V(DEBUG, TAG, "Number of SubOwner = %zd", 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."); @@ -1130,3 +2591,38 @@ void RestoreDoxmToInitState() } } } + +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; +} +