X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fsecurity%2Fprovisioning%2Fsrc%2Fownershiptransfermanager.c;h=4a9021ac3d3fba890cd4f2d5decd11fbcf63c509;hb=62f5a2e679ddc2706caa1aead719697209318609;hp=ba284f6d3d311c7f288d9b4de0f3e25f788c1c36;hpb=8945accc6fbae437bc06c8ebf207d4b029f8566d;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c index ba284f6..4a9021a 100644 --- a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c +++ b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c @@ -30,11 +30,20 @@ #define _POSIX_C_SOURCE 200809L #endif +#include "iotivity_config.h" +#ifdef HAVE_TIME_H #include +#endif +#ifdef HAVE_UNISTD_H #include +#endif +#ifdef HAVE_SYS_TIME_H #include +#endif #include #include +#include +#include #include "logger.h" #include "oic_malloc.h" @@ -42,9 +51,12 @@ #include "cacommon.h" #include "cainterface.h" #include "base64.h" +#if defined (__TIZENRT__) +#include +#else #include "cJSON.h" -#include "global.h" - +#endif +#include "utlist.h" #include "srmresourcestrings.h" #include "doxmresource.h" #include "pstatresource.h" @@ -53,36 +65,188 @@ #include "ownershiptransfermanager.h" #include "securevirtualresourcetypes.h" #include "oxmjustworks.h" +#include "oxmrandompin.h" +#include "oxmrawpublickey.h" +#include "oxmmanufacturercert.h" +#include "secureresourceprovider.h" + +#ifdef MULTIPLE_OWNER +#include "oxmpreconfpin.h" +#endif //MULTIPLE_OWNER +#include "otmcontextlist.h" #include "pmtypes.h" #include "pmutility.h" #include "srmutility.h" #include "provisioningdatabasemanager.h" -#include "oxmrandompin.h" +#include "ocpayload.h" +#include "payload_logging.h" +#include "pkix_interface.h" +#include "oxmverifycommon.h" +#include "psinterface.h" -#define TAG "OTM" +#define TAG "OIC_OTM" -/** - * Array to store the callbacks for each owner transfer method. - */ -static OTMCallbackData_t g_OTMDatas[OIC_OXM_COUNT]; -/** - * Variable for storing provisioning tool's provisioning capabilities - * Must be in decreasing order of preference. More prefered method should - * have lower array index. - */ -static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN }; +#define ALLOWED_OXM 1 +#define NOT_ALLOWED_OXM 0 /** - * Number of supported provisioning methods - * current version supports only one. + * List of allowed oxm list. + * All oxm methods are allowed as default. */ -static size_t gNumOfProvisioningMethodsPT = 1; +#ifdef MULTIPLE_OWNER +static uint8_t g_OxmAllowStatus[OXM_IDX_COUNT] = {ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM, + ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM, + ALLOWED_OXM, NOT_ALLOWED_OXM}; +#else +static uint8_t g_OxmAllowStatus[OXM_IDX_COUNT] = {ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM, + ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM, + NOT_ALLOWED_OXM}; +#endif + +static OicSecOxm_t selectOTMcb_default(const OicSecOxm_t* otmList, const uint32_t len); +static OTMSelectMethodCallback g_selectOTMCB = selectOTMcb_default; + +OCStackResult OTMSetOTCallback(OicSecOxm_t oxm, OTMCallbackData_t* callbacks) +{ + OCStackResult res = OC_STACK_INVALID_PARAM; + + OIC_LOG(INFO, TAG, "IN OTMSetOTCallback"); + + VERIFY_NON_NULL(TAG, callbacks, ERROR); + +#ifdef MULTIPLE_OWNER + VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > oxm || OIC_PRECONFIG_PIN == oxm || OIC_MV_JUST_WORKS == oxm + || OIC_CON_MFG_CERT == oxm || OIC_RAW_PUB_KEY == oxm), ERROR); +#else + VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > oxm || OIC_MV_JUST_WORKS == oxm || OIC_CON_MFG_CERT == oxm || OIC_RAW_PUB_KEY == oxm), ERROR); +#endif // MULTIPLE_OWNER + + switch(oxm) + { + case OIC_JUST_WORKS: + callbacks->loadSecretCB = LoadSecretJustWorksCallback; + callbacks->createSecureSessionCB = CreateSecureSessionJustWorksCallback; + callbacks->createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload; + break; + case OIC_RANDOM_DEVICE_PIN: + callbacks->loadSecretCB = InputPinCodeCallback; + callbacks->createSecureSessionCB = CreateSecureSessionRandomPinCallback; + callbacks->createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload; + break; + case OIC_MANUFACTURER_CERTIFICATE: + callbacks->loadSecretCB = PrepareMCertificateCallback; + callbacks->createSecureSessionCB = CreateSecureSessionMCertificateCallback; + callbacks->createSelectOxmPayloadCB = CreateMCertificateBasedSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreateMCertificateBasedOwnerTransferPayload; + break; + case OIC_DECENTRALIZED_PUBLIC_KEY: + OIC_LOG(ERROR, TAG, "OIC_DECENTRALIZED_PUBLIC_KEY not supported yet."); + return OC_STACK_INVALID_METHOD; +#ifdef MULTIPLE_OWNER + case OIC_PRECONFIG_PIN: + callbacks->loadSecretCB = LoadPreconfigPinCodeCallback; + callbacks->createSecureSessionCB = CreateSecureSessionPreconfigPinCallback; + callbacks->createSelectOxmPayloadCB = CreatePreconfigPinBasedSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreatePreconfigPinBasedOwnerTransferPayload; + break; +#endif //MULTIPLE_OWNER + case OIC_MV_JUST_WORKS: + callbacks->loadSecretCB = LoadSecretJustWorksCallback; + callbacks->createSecureSessionCB = CreateSecureSessionJustWorksCallback; + callbacks->createSelectOxmPayloadCB = CreateMVJustWorksSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload; + break; + case OIC_CON_MFG_CERT: + callbacks->loadSecretCB = PrepareMCertificateCallback; + callbacks->createSecureSessionCB = CreateSecureSessionMCertificateCallback; + callbacks->createSelectOxmPayloadCB = CreateConMCertificateBasedSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreateMCertificateBasedOwnerTransferPayload; + break; + case OIC_RAW_PUB_KEY: + callbacks->loadSecretCB = GetMasterRPKCallback; + callbacks->createSecureSessionCB = CreateSecureSessionRPKCallback; + callbacks->createSelectOxmPayloadCB = CreateRPKBasedSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreateRPKBasedOwnerTransferPayload; + break; + default: + OIC_LOG_V(ERROR, TAG, "Unknown OxM : %d", (int)oxm); + return OC_STACK_INVALID_PARAM; + break; + } + + res = OC_STACK_OK; +exit: + OIC_LOG(INFO, TAG, "OUT OTMSetOTCallback"); + return res; +} + +void SetSelectOTMCB(OTMSelectMethodCallback selectOTMcb) +{ + g_selectOTMCB = selectOTMcb; + return; +} + +void UnsetSelectOTMCB() +{ + g_selectOTMCB = NULL; + return; +} /** - * Variables for pointing the OTMContext to be used in the DTLS handshake result callback. + * Internal API to convert OxM value to index of oxm allow table. */ -static OTMContext_t* g_otmCtx = NULL; +static OxmAllowTableIdx_t GetOxmAllowTableIdx(OicSecOxm_t oxm) +{ + switch(oxm) + { + case OIC_JUST_WORKS: + return OXM_IDX_JUST_WORKS; + case OIC_RANDOM_DEVICE_PIN: + return OXM_IDX_RANDOM_DEVICE_PIN; + case OIC_MANUFACTURER_CERTIFICATE: + return OXM_IDX_MANUFACTURER_CERTIFICATE; + case OIC_DECENTRALIZED_PUBLIC_KEY: + return OXM_IDX_DECENTRALIZED_PUBLIC_KEY; + case OIC_MV_JUST_WORKS: + return OXM_IDX_MV_JUST_WORKS; + case OIC_RAW_PUB_KEY: + return OXM_IDX_RAW_PUBLIC_KEY; + case OIC_CON_MFG_CERT: + return OXM_IDX_CON_MFG_CERT; +#ifdef MULTIPLE_OWNER + case OIC_PRECONFIG_PIN: + return OXM_IDX_PRECONFIG_PIN; +#endif + default: + return OXM_IDX_UNKNOWN; + } +} + +OicSecOxm_t selectOTMcb_default(const OicSecOxm_t* otmList, const uint32_t len) +{ + OIC_LOG(INFO, TAG, "IN selectOTMcb_default"); + OicSecOxm_t ret = -1; + VERIFY_NON_NULL(TAG, otmList, ERROR); + VERIFY_SUCCESS(TAG, (len > 0), ERROR); + + ret = otmList[len-1]; + + for (size_t i = 0; i < len; i++) + { + if (OIC_RANDOM_DEVICE_PIN == otmList[i]) + { + ret = OIC_RANDOM_DEVICE_PIN; + break; + } + } + +exit: + OIC_LOG(INFO, TAG, "OUT selectOTMcb_default"); + return ret; +} /** * Function to select appropriate provisioning method. @@ -90,29 +254,119 @@ static OTMContext_t* g_otmCtx = NULL; * @param[in] supportedMethods Array of supported methods * @param[in] numberOfMethods number of supported methods * @param[out] selectedMethod Selected methods + * @param[in] ownerType type of owner device (SUPER_OWNER or SUB_OWNER) * @return OC_STACK_OK on success */ -static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethods, - size_t numberOfMethods, - OicSecOxm_t *selectedMethod) +OCStackResult OTMSelectOwnershipTransferMethod(const OicSecOxm_t *supportedMethods, + size_t numberOfMethods, OicSecOxm_t *selectedMethod, OwnerType_t ownerType) { + bool isOxmSelected = false; + OxmAllowTableIdx_t selectedOxmIdx = OXM_IDX_UNKNOWN; + OIC_LOG(DEBUG, TAG, "IN SelectProvisioningMethod"); - if(numberOfMethods == 0 || !supportedMethods) + if (numberOfMethods == 0 || !supportedMethods) { OIC_LOG(WARNING, TAG, "Could not find a supported OxM."); return OC_STACK_ERROR; } - *selectedMethod = supportedMethods[0]; - for(size_t i = 0; i < numberOfMethods; i++) + switch(ownerType) { - if(*selectedMethod < supportedMethods[i]) + case SUPER_OWNER: + { + if (g_selectOTMCB) + { + uint32_t methNum = 0; + OicSecOxm_t list[10] = {0}; + + for (size_t i = 0; i < numberOfMethods; i++) + { + selectedOxmIdx = GetOxmAllowTableIdx(supportedMethods[i]); + if (OXM_IDX_COUNT <= selectedOxmIdx) + { + OIC_LOG(WARNING, TAG, "Invalid oxm index to access OxM allow table"); + continue; + } + #ifdef MULTIPLE_OWNER + if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx] && + OXM_IDX_PRECONFIG_PIN != selectedOxmIdx) + #else + + if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx]) + #endif //MULTIPLE_OWNER + { + list[methNum] = supportedMethods[i]; + methNum++; + } + } + *selectedMethod = g_selectOTMCB(list, methNum); + isOxmSelected = true; + } + else + { + for (size_t i = 0; i < numberOfMethods; i++) + { + selectedOxmIdx = GetOxmAllowTableIdx(supportedMethods[i]); + if (OXM_IDX_COUNT <= selectedOxmIdx) + { + OIC_LOG(WARNING, TAG, "Invalid oxm index to access OxM allow table"); + continue; + } + #ifdef MULTIPLE_OWNER + if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx] && + OXM_IDX_PRECONFIG_PIN != selectedOxmIdx) + #else + + if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx]) + #endif //MULTIPLE_OWNER + { + *selectedMethod = supportedMethods[i]; + isOxmSelected = true; + } + } + } + } + break; +#ifdef MULTIPLE_OWNER + case SUB_OWNER: + { + for (size_t i = 0; i < numberOfMethods; i++) + { + selectedOxmIdx = GetOxmAllowTableIdx(supportedMethods[i]); + if (OXM_IDX_COUNT <= selectedOxmIdx) + { + OIC_LOG(WARNING, TAG, "Invalid oxm index to access OxM allow table"); + continue; + } + + //in case of MOT, only Random PIN & Preconfigured PIN based OxM is allowed + if (ALLOWED_OXM == g_OxmAllowStatus[selectedOxmIdx] && + (OXM_IDX_RANDOM_DEVICE_PIN == selectedOxmIdx || + OXM_IDX_PRECONFIG_PIN == selectedOxmIdx)) + { + *selectedMethod = supportedMethods[i]; + isOxmSelected = true; + } + } + } + break; +#endif + default: { - *selectedMethod = supportedMethods[i]; + OIC_LOG_V(ERROR, TAG, "Unknown owner type or Not supported owner type : %d", ownerType); + return OC_STACK_INVALID_PARAM; } } + if (!isOxmSelected) + { + OIC_LOG(ERROR, TAG, "Can not find the allowed OxM."); + return OC_STACK_NOT_ALLOWED_OXM; + } + + OIC_LOG(DEBUG, TAG, "OUT SelectProvisioningMethod"); + return OC_STACK_OK; } @@ -127,29 +381,8 @@ static void SelectOperationMode(const OCProvisionDev_t *selectedDeviceInfo, OicSecDpom_t *selectedMode) { OIC_LOG(DEBUG, TAG, "IN SelectOperationMode"); - - size_t i = 0; - size_t j = 0; - - while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen) - { - if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j]) - { - i++; - } - else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i]) - { - j++; - } - else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */ - { - *selectedMode = gProvisioningToolCapability[j]; - break; - } - } + *selectedMode = selectedDeviceInfo->pstat->sm[0]; OIC_LOG_V(DEBUG, TAG, "Selected Operation Mode = %d", *selectedMode); - - OIC_LOG(DEBUG, TAG, "OUT SelectOperationMode"); } /** @@ -163,13 +396,21 @@ static void SelectOperationMode(const OCProvisionDev_t *selectedDeviceInfo, */ static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice); +/* + * Internal function to setup & cleanup PDM to performing provisioning. + * + * @param[in] selectedDevice selected device information to performing provisioning. + * @return OC_STACK_OK on success + */ +static OCStackResult SetupPDM(const OCProvisionDev_t* selectedDevice); + /** * Function to update owner transfer mode * * @param[in] otmCtx Context value of ownership transfer. * @return OC_STACK_OK on success */ -static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx); +static OCStackResult PostOwnerTransferModeToResource(OTMContext_t* otmCtx); /** * Function to send request to resource to get its pstat resource information. @@ -187,7 +428,7 @@ static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx); * @param[in] otmCtx Context value of ownership transfer. * @return OC_STACK_OK on success */ -static OCStackResult PutOwnerUuid(OTMContext_t* otmCtx); +static OCStackResult PostOwnerUuid(OTMContext_t* otmCtx); /** * Function to update the operation mode. As per the spec. Operation mode in client driven @@ -196,7 +437,7 @@ static OCStackResult PutOwnerUuid(OTMContext_t* otmCtx); * @param[in] otmCtx Context value of ownership transfer. * @return OC_STACK_OK on success */ -static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx); +static OCStackResult PostUpdateOperationMode(OTMContext_t* otmCtx); /** * Function to update the owner credential to new device @@ -205,7 +446,15 @@ static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx); * @param[in] selectedOperationMode selected operation mode * @return OC_STACK_OK on success */ -static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx); +static OCStackResult PostOwnerCredential(OTMContext_t* otmCtx); + +/** + * Function to update the owner ACL to new device. + * + * @param[in] otmCtx Context value of ownership transfer. + * @return OC_STACK_OK on success + */ +static OCStackResult PostOwnerAcl(OTMContext_t* otmCtx); /** * Function to send ownerShip info. @@ -214,27 +463,27 @@ static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx); * @param[in] otmCtx Context value of ownership transfer. * @return OC_STACK_OK on success */ -static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx); +static OCStackResult PostOwnershipInformation(OTMContext_t* otmCtx); /** - * Function to update pstat when finalize provisioning. - * This function would update 'cm' as bx0011,1100 and 'tm' as bx0000,0000. + * Function to update pstat as Ready for provisioning. + * This function would update 'cm' from bx0000,0010 to bx0000,0000. * * @param[in] ctx context value passed to callback from calling function. * @param[in] selectedDevice selected device information to performing provisioning. * @return OC_STACK_OK on success */ -static OCStackResult PutProvisioningStatus(OTMContext_t* otmCtx); +static OCStackResult PostProvisioningStatus(OTMContext_t* otmCtx); -/* - * Function to finalize provisioning. - * This function will send default ACL and commit hash. +/** + * Function to update pstat as Ready for Normal Operation. + * This function would update 'isop' from false to true. * - * @param[in] otmCtx Context value of ownership transfer. + * @param[in] ctx context value passed to callback from calling function. + * @param[in] selectedDevice selected device information to performing provisioning. * @return OC_STACK_OK on success */ -static OCStackResult FinalizeProvisioning(OTMContext_t* otmCtx); - +static OCStackResult PostNormalOperationStatus(OTMContext_t* otmCtx); static bool IsComplete(OTMContext_t* otmCtx) { @@ -255,60 +504,128 @@ static bool IsComplete(OTMContext_t* otmCtx) * @param[in,out] otmCtx Context value of ownership transfer. * @param[in] res result of provisioning */ -static void SetResult(OTMContext_t* otmCtx, const OCStackResult res) +void SetResult(OTMContext_t* otmCtx, const OCStackResult res) { OIC_LOG_V(DEBUG, TAG, "IN SetResult : %d ", res); - if(!otmCtx) + if(NULL == otmCtx || NULL == otmCtx->selectedDeviceInfo + || NULL == otmCtx->selectedDeviceInfo->doxm) { OIC_LOG(WARNING, TAG, "OTMContext is NULL"); return; } - if(otmCtx->selectedDeviceInfo) + //If OTM Context was removed from previous response handler, just exit the current OTM process. + if(NULL == GetOTMContext(otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort)) + { + OIC_LOG(WARNING, TAG, "Current OTM Process has already ended."); + } + + //Revert psk_info callback and new deivce uuid in case of random PIN OxM + if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel) { - //Revert psk_info callback and new deivce uuid in case of random PIN OxM - if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel) + if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials)) { - if(CA_STATUS_OK != CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials)) - { - OIC_LOG(WARNING, TAG, "Failed to revert is DTLS credential handler."); - } - OicUuid_t emptyUuid = { .id={0}}; - SetUuidForRandomPinOxm(&emptyUuid); + OIC_LOG(WARNING, TAG, "Failed to revert is DTLS credential handler."); + } + OicUuid_t emptyUuid = { .id={0}}; + SetUuidForPinBasedOxm(&emptyUuid); + } + else if(OIC_MANUFACTURER_CERTIFICATE == otmCtx->selectedDeviceInfo->doxm->oxmSel || + OIC_CON_MFG_CERT == otmCtx->selectedDeviceInfo->doxm->oxmSel) + { + //Revert back certificate related callbacks. + if(CA_STATUS_OK != CAregisterPkixInfoHandler(GetPkixInfo)) + { + OIC_LOG(WARNING, TAG, "Failed to revert PkixInfoHandler."); + } + if(CA_STATUS_OK != CAregisterGetCredentialTypesHandler(InitCipherSuiteList)) + { + OIC_LOG(WARNING, TAG, "Failed to revert CredentialTypesHandler."); } + } - for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++) + for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++) + { + if(memcmp(otmCtx->selectedDeviceInfo->doxm->deviceID.id, + otmCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0) { - if(memcmp(otmCtx->selectedDeviceInfo->doxm->deviceID.id, - otmCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0) + otmCtx->ctxResultArray[i].res = res; + if(OC_STACK_OK != res && OC_STACK_CONTINUE != res && OC_STACK_DUPLICATE_REQUEST != res) { - otmCtx->ctxResultArray[i].res = res; - if(OC_STACK_OK != res) + otmCtx->ctxHasError = true; + if (OC_STACK_OK != PDMDeleteDevice(&otmCtx->ctxResultArray[i].deviceId)) + { + OIC_LOG(WARNING, TAG, "Internal error in PDMDeleteDevice"); + } + CAEndpoint_t endpoint; + memcpy(&endpoint, &(otmCtx->selectedDeviceInfo->endpoint), sizeof(CAEndpoint_t)); + endpoint.port = otmCtx->selectedDeviceInfo->securePort; + if (CA_STATUS_OK != CAcloseSslConnection(&endpoint)) { - otmCtx->ctxHasError = true; + OIC_LOG(WARNING, TAG, "Failed to close Secure session"); } } } + } - g_otmCtx = NULL; + //In case of duplicated OTM process, OTMContext and OCDoHandle should not be removed. + if(OC_STACK_DUPLICATE_REQUEST != res) + { + //Remove the current OTM Context from OTM queue + RemoveOTMContext(otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort); - //If all request is completed, invoke the user callback. - if(IsComplete(otmCtx)) + //If there is a request being performed, cancel it to prevent retransmission. + if(otmCtx->ocDoHandle) { - otmCtx->ctxResultCallback(otmCtx->userCtx, otmCtx->ctxResultArraySize, - otmCtx->ctxResultArray, otmCtx->ctxHasError); - OICFree(otmCtx->ctxResultArray); - OICFree(otmCtx); + OIC_LOG_V(DEBUG, TAG, "OCCancel - %s : %d", + otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort); + if(OC_STACK_OK != OCCancel(otmCtx->ocDoHandle, OC_HIGH_QOS, NULL, 0)) + { + OIC_LOG(WARNING, TAG, "Failed to remove registered callback"); + } + else + { + otmCtx->ocDoHandle = NULL; + } } - else + } + + //If all OTM process is complete, invoke the user callback. + if(IsComplete(otmCtx)) + { + if(OC_STACK_OK != res && OC_STACK_CONTINUE != res && OC_STACK_DUPLICATE_REQUEST != res) { - if(OC_STACK_OK != StartOwnershipTransfer(otmCtx, - otmCtx->selectedDeviceInfo->next)) + // Reset doxm and pstat properties to pre-Ownership Transfer state + OIC_LOG(DEBUG, TAG, "Resetting doxm and pstat properties"); + if(otmCtx->selectedDeviceInfo->doxm) + { + OicUuid_t emptyUuid = {.id = {0}}; + memcpy(&(otmCtx->selectedDeviceInfo->doxm->owner), &emptyUuid, sizeof(OicUuid_t)); + otmCtx->selectedDeviceInfo->doxm->owned = false; + } + if(otmCtx->selectedDeviceInfo->pstat) { - OIC_LOG(ERROR, TAG, "Failed to StartOwnershipTransfer"); + otmCtx->selectedDeviceInfo->pstat->isOp = false; + otmCtx->selectedDeviceInfo->pstat->cm |= TAKE_OWNER; } } + + otmCtx->ctxResultCallback(otmCtx->userCtx, otmCtx->ctxResultArraySize, + otmCtx->ctxResultArray, otmCtx->ctxHasError); + OICFree(otmCtx->ctxResultArray); + OICFree(otmCtx); + } + else + { + if(OC_STACK_OK != StartOwnershipTransfer(otmCtx, + otmCtx->selectedDeviceInfo->next)) + { + OIC_LOG(ERROR, TAG, "Failed to StartOwnershipTransfer"); + } } OIC_LOG(DEBUG, TAG, "OUT SetResult"); @@ -323,72 +640,165 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res) */ void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info) { - if(g_otmCtx && endpoint && info) + OIC_LOG(DEBUG, TAG, "IN DTLSHandshakeCB"); + if(NULL != endpoint && NULL != info) { OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d", endpoint->addr, endpoint->port, info->result); - //Make sure the address matches. - if(strncmp(g_otmCtx->selectedDeviceInfo->endpoint.addr, - endpoint->addr, - sizeof(endpoint->addr)) == 0 && - g_otmCtx->selectedDeviceInfo->securePort == endpoint->port) + OTMContext_t* otmCtx = GetOTMContext(endpoint->addr, endpoint->port); + if(otmCtx) { - OCStackResult res = OC_STACK_ERROR; - - //In case of success, send next coaps request. - if(CA_STATUS_OK == info->result) - { - //Send request : PUT /oic/sec/doxm [{... , "devowner":"PT's UUID"}] - res = PutOwnerUuid(g_otmCtx); - if(OC_STACK_OK != res) - { - OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to send owner information"); - SetResult(g_otmCtx, res); - } - } - //In case of failure, re-start the ownership transfer in case of PIN OxM - else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result) + OicSecDoxm_t* newDevDoxm = otmCtx->selectedDeviceInfo->doxm; + if(NULL != newDevDoxm) { - g_otmCtx->selectedDeviceInfo->doxm->owned = false; - g_otmCtx->attemptCnt++; + OicUuid_t emptyUuid = {.id={0}}; - if(g_otmCtx->selectedDeviceInfo->doxm->oxmSel == OIC_RANDOM_DEVICE_PIN) + //Make sure the address matches. + if(strncmp(otmCtx->selectedDeviceInfo->endpoint.addr, + endpoint->addr, + sizeof(endpoint->addr)) == 0 && + otmCtx->selectedDeviceInfo->securePort == endpoint->port) { - /* - res = RemoveCredential(&g_otmCtx->subIdForPinOxm); - if(OC_STACK_RESOURCE_DELETED != res) - { - OIC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res); - SetResult(g_otmCtx, res); - return; - }*/ + OCStackResult res = OC_STACK_ERROR; - if(WRONG_PIN_MAX_ATTEMP > g_otmCtx->attemptCnt) + //If temporal secure sesstion established successfully + if(CA_STATUS_OK == info->result && + false == newDevDoxm->owned && + memcmp(&(newDevDoxm->owner), &emptyUuid, sizeof(OicUuid_t)) == 0) { - res = StartOwnershipTransfer(g_otmCtx, g_otmCtx->selectedDeviceInfo); + //In case of Mutual Verified Just-Works, display mutualVerifNum + if (OIC_MV_JUST_WORKS == newDevDoxm->oxmSel) + { + uint8_t preMutualVerifNum[OWNER_PSK_LENGTH_128] = {0}; + uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN] = {0}; + OicUuid_t deviceID = {.id = {0}}; + + //Generate mutualVerifNum + char label[LABEL_LEN] = {0}; + snprintf(label, LABEL_LEN, "%s%s", MUTUAL_VERIF_NUM, OXM_MV_JUST_WORKS); + res = GetDoxmDeviceID(&deviceID); + if (OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID"); + SetResult(otmCtx, res); + return; + } + + CAResult_t pskRet = CAGenerateOwnerPSK(endpoint, + (uint8_t *)label, + strlen(label), + deviceID.id, sizeof(deviceID.id), + newDevDoxm->deviceID.id, sizeof(newDevDoxm->deviceID.id), + preMutualVerifNum, OWNER_PSK_LENGTH_128); + if (CA_STATUS_OK != pskRet) + { + OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential"); + SetResult(otmCtx, OC_STACK_ERROR); + return; + } + + memcpy(mutualVerifNum, preMutualVerifNum + OWNER_PSK_LENGTH_128 - sizeof(mutualVerifNum), + sizeof(mutualVerifNum)); + res = VerifyOwnershipTransfer(mutualVerifNum, DISPLAY_NUM); + if (OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "Error while displaying mutualVerifNum"); + SetResult(otmCtx, res); + return; + } + } + //In case of confirmed manufacturer cert, display message + else if (OIC_MANUFACTURER_CERTIFICATE == newDevDoxm->oxmSel || OIC_CON_MFG_CERT == newDevDoxm->oxmSel) + { + res = VerifyOwnershipTransfer(NULL, DISPLAY_NUM); + if (OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "Error while displaying message"); + SetResult(otmCtx, res); + return; + } + } + + //Send request : POST /oic/sec/doxm [{... , "devowner":"PT's UUID"}] + res = PostOwnerUuid(otmCtx); if(OC_STACK_OK != res) { - SetResult(g_otmCtx, res); - OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer"); + OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to send owner information"); + SetResult(otmCtx, res); } } - else + //In case of authentication failure + else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result) { - SetResult(g_otmCtx, OC_STACK_AUTHENTICATION_FAILURE); + //in case of error from owner credential + if(memcmp(&(newDevDoxm->owner), &emptyUuid, sizeof(OicUuid_t)) != 0 && + true == newDevDoxm->owned) + { + OIC_LOG(ERROR, TAG, "The owner credential may incorrect."); + + if(OC_STACK_OK != RemoveCredential(&(newDevDoxm->deviceID))) + { + OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential"); + } + SetResult(otmCtx, OC_STACK_AUTHENTICATION_FAILURE); + } + //in case of error from wrong PIN, re-start the ownership transfer + else if(OIC_RANDOM_DEVICE_PIN == newDevDoxm->oxmSel) + { + OIC_LOG(ERROR, TAG, "The PIN number may incorrect."); + + memcpy(&(newDevDoxm->owner), &emptyUuid, sizeof(OicUuid_t)); + newDevDoxm->owned = false; + otmCtx->attemptCnt++; + + RemoveOTMContext(otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort); + + // In order to re-start ownership transfer, device information should be deleted from PDM. + res = PDMDeleteDevice(&(otmCtx->selectedDeviceInfo->doxm->deviceID)); + if (OC_STACK_OK != res) + { + SetResult(otmCtx, res); + OIC_LOG(ERROR, TAG, "Failed to PDMDeleteDevice"); + } + else + { + if(WRONG_PIN_MAX_ATTEMP > otmCtx->attemptCnt) + { + res = StartOwnershipTransfer(otmCtx, otmCtx->selectedDeviceInfo); + if(OC_STACK_OK != res) + { + SetResult(otmCtx, res); + OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer"); + } + } + else + { + OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts."); + SetResult(otmCtx, OC_STACK_AUTHENTICATION_FAILURE); + } + } + } + else + { + OIC_LOG(ERROR, TAG, "Failed to establish secure session."); + SetResult(otmCtx, OC_STACK_AUTHENTICATION_FAILURE); + } } } - else - { - SetResult(g_otmCtx, OC_STACK_AUTHENTICATION_FAILURE); - } } } + else + { + OIC_LOG(ERROR, TAG, "Can not find the OTM Context."); + } } + OIC_LOG(DEBUG, TAG, "OUT DTLSHandshakeCB"); } /** - * Function to save ownerPSK at provisioning tool end. + * Function to save the Owner/SubOwner PSK. * * @param[in] selectedDeviceInfo selected device information to performing provisioning. * @return OC_STACK_OK on success @@ -404,42 +814,93 @@ static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo) OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr); endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0'; endpoint.port = selectedDeviceInfo->securePort; + endpoint.adapter = selectedDeviceInfo->endpoint.adapter; - OicUuid_t ptDeviceID = {.id={0}}; - if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID)) + OicUuid_t ownerDeviceID = {.id={0}}; + if (OC_STACK_OK != GetDoxmDeviceID(&ownerDeviceID)) { - OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID"); return res; } uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0}; + OicSecKey_t ownerKey = {.data=ownerPSK, .len=OWNER_PSK_LENGTH_128, .encoding=OIC_ENCODING_RAW}; //Generating OwnerPSK CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint, (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel), strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)), - ptDeviceID.id, sizeof(ptDeviceID.id), + ownerDeviceID.id, sizeof(ownerDeviceID.id), selectedDeviceInfo->doxm->deviceID.id, sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK, OWNER_PSK_LENGTH_128); if (CA_STATUS_OK == pskRet) { - OIC_LOG(INFO, TAG,"ownerPSK dump:\n"); - OIC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128); + OIC_LOG(DEBUG, TAG,"Owner PSK dump:\n"); + OIC_LOG_BUFFER(DEBUG, TAG,ownerPSK, OWNER_PSK_LENGTH_128); //Generating new credential for provisioning tool - size_t ownLen = 1; - uint32_t outLen = 0; - - char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {}; - B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff), - &outLen); - VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR); - OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID, - SYMMETRIC_PAIR_WISE_KEY, NULL, - base64Buff, ownLen, &ptDeviceID); + SYMMETRIC_PAIR_WISE_KEY, NULL, + &ownerKey, &ownerDeviceID, NULL); + OICClearMemory(ownerPSK, sizeof(ownerPSK)); VERIFY_NON_NULL(TAG, cred, ERROR); + uint32_t outSize = 0; + size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1)); + char* b64Buf = (char *)OICCalloc(1, b64BufSize); + VERIFY_NON_NULL(TAG, b64Buf, ERROR); + b64Encode(cred->privateData.data, cred->privateData.len, b64Buf, b64BufSize, &outSize); + + OICFree( cred->privateData.data ); + cred->privateData.data = (uint8_t *)OICCalloc(1, outSize + 1); + if (cred->privateData.data == NULL) + { + OICFree(b64Buf); + res = OC_STACK_ERROR; + goto exit; + } + + strncpy((char*)(cred->privateData.data), b64Buf, outSize); + cred->privateData.data[outSize] = '\0'; + cred->privateData.encoding = OIC_ENCODING_BASE64; + cred->privateData.len = outSize; + OICFree(b64Buf); + + //Finding previous ownerPSK. + const OicSecCred_t* credList = GetCredList(); + const OicSecCred_t* prevCred = NULL; + uint16_t credId = 0; + LL_FOREACH(credList, prevCred) + { + //OwnerPSK's type is SYMMETRIC_PAIR_WISE_KEY + if (SYMMETRIC_PAIR_WISE_KEY == prevCred->credType && + 0 == memcmp(prevCred->subject.id, cred->subject.id, sizeof(cred->subject.id))) + { + credId = prevCred->credId; + break; + } + } + + //If duplicate owner PSK is exists, remove it. + if(0 < credId) + { + OIC_LOG(WARNING, TAG, "Duplicate OwnerPSK was detected."); + OIC_LOG(WARNING, TAG, "[Subject] : "); + OIC_LOG_BUFFER(WARNING, TAG, prevCred->subject.id, sizeof(prevCred->subject.id)); + OIC_LOG_V(WARNING, TAG, "[Encoding Type] : %d", prevCred->privateData.encoding); + OIC_LOG(DEBUG, TAG, "[Private Data] : "); + OIC_LOG_BUFFER(DEBUG, TAG, prevCred->privateData.data, prevCred->privateData.len); + OIC_LOG(WARNING, TAG, "Previous OwnerPSK will be removed."); + + res = RemoveCredentialByCredId(credId); + if(OC_STACK_RESOURCE_DELETED != res) + { + OIC_LOG(ERROR, TAG, "Failed to remove the previous OwnerPSK"); + DeleteCredList(cred); + goto exit; + } + } + res = AddCredential(cred); if(res != OC_STACK_OK) { @@ -475,8 +936,9 @@ static OCStackApplicationResult OwnerTransferModeHandler(void *ctx, OCDoHandle U VERIFY_NON_NULL(TAG, ctx, WARNING); OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; (void)UNUSED; - if(clientResponse->result == OC_STACK_OK) + if (OC_STACK_RESOURCE_CHANGED == clientResponse->result) { OIC_LOG(INFO, TAG, "OwnerTransferModeHandler : response result = OC_STACK_OK"); //Send request : GET /oic/sec/pstat @@ -518,6 +980,7 @@ static OCStackApplicationResult ListMethodsHandler(void *ctx, OCDoHandle UNUSED, VERIFY_NON_NULL(TAG, ctx, WARNING); OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; (void)UNUSED; if (OC_STACK_OK == clientResponse->result) { @@ -534,12 +997,20 @@ static OCStackApplicationResult ListMethodsHandler(void *ctx, OCDoHandle UNUSED, SetResult(otmCtx, OC_STACK_ERROR); return OC_STACK_DELETE_TRANSACTION; } - - OicSecPstat_t* pstat = JSONToPstatBin( - ((OCSecurityPayload*)clientResponse->payload)->securityData); - if(NULL == pstat) + OicSecPstat_t* pstat = NULL; + OCStackResult result = CBORPayloadToPstat( + ((OCSecurityPayload*)clientResponse->payload)->securityData, + ((OCSecurityPayload*)clientResponse->payload)->payloadSize, + &pstat); + if(NULL == pstat || result != OC_STACK_OK) + { + OIC_LOG(ERROR, TAG, "Error while converting cbor to pstat."); + SetResult(otmCtx, OC_STACK_ERROR); + return OC_STACK_DELETE_TRANSACTION; + } + if(false == (TAKE_OWNER & pstat->cm)) { - OIC_LOG(ERROR, TAG, "Error while converting json to pstat bin"); + OIC_LOG(ERROR, TAG, "Device pairing mode enabling owner transfer operations is disabled"); SetResult(otmCtx, OC_STACK_ERROR); return OC_STACK_DELETE_TRANSACTION; } @@ -548,8 +1019,8 @@ static OCStackApplicationResult ListMethodsHandler(void *ctx, OCDoHandle UNUSED, //Select operation mode (Currently supported SINGLE_SERVICE_CLIENT_DRIVEN only) SelectOperationMode(otmCtx->selectedDeviceInfo, &(otmCtx->selectedDeviceInfo->pstat->om)); - //Send request : PUT /oic/sec/pstat [{"om":"bx11", .. }] - OCStackResult res = PutUpdateOperationMode(otmCtx); + //Send request : POST /oic/sec/pstat [{"om":"bx11", .. }] + OCStackResult res = PostUpdateOperationMode(otmCtx); if (OC_STACK_OK != res) { OIC_LOG(ERROR, TAG, "Error while updating operation mode."); @@ -568,6 +1039,13 @@ exit: return OC_STACK_DELETE_TRANSACTION; } +static void deleteCallback(void *ctx) +{ + OC_UNUSED(ctx); + OIC_LOG_V(DEBUG, TAG, "%s: otm context deleted", __func__); +} + + /** * Response handler for update owner uuid request. * @@ -587,11 +1065,28 @@ static OCStackApplicationResult OwnerUuidUpdateHandler(void *ctx, OCDoHandle UNU (void)UNUSED; OCStackResult res = OC_STACK_OK; OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; - if(OC_STACK_OK == clientResponse->result) + if(OC_STACK_RESOURCE_CHANGED == clientResponse->result) { if(otmCtx && otmCtx->selectedDeviceInfo) { + //In case of Mutual Verified Just-Works, wait for user confirmation + if (OIC_MV_JUST_WORKS == otmCtx->selectedDeviceInfo->doxm->oxmSel) + { + res = VerifyOwnershipTransfer(NULL, USER_CONFIRM); + if (OC_STACK_OK != res) + { + if (OC_STACK_OK != SRPResetDevice(otmCtx->selectedDeviceInfo, deleteCallback)) + { + OIC_LOG(WARNING, TAG, "OwnerUuidUpdateHandler : SRPResetDevice error"); + } + OIC_LOG(ERROR, TAG, "OwnerUuidUpdateHandler:Failed to verify user confirm"); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } + } + res = SaveOwnerPSK(otmCtx->selectedDeviceInfo); if(OC_STACK_OK != res) { @@ -600,12 +1095,12 @@ static OCStackApplicationResult OwnerUuidUpdateHandler(void *ctx, OCDoHandle UNU return OC_STACK_DELETE_TRANSACTION; } - //PUT owner credential to new device according to security spec B. - res = PutOwnerCredential(otmCtx); + //POST owner credential to new device according to security spec B. + res = PostOwnerCredential(otmCtx); if(OC_STACK_OK != res) { OIC_LOG(ERROR, TAG, - "OwnerUuidUpdateHandler:Failed to send PUT request for onwer credential"); + "OwnerUuidUpdateHandler:Failed to send PosT request for onwer credential"); SetResult(otmCtx, res); return OC_STACK_DELETE_TRANSACTION; } @@ -613,8 +1108,25 @@ static OCStackApplicationResult OwnerUuidUpdateHandler(void *ctx, OCDoHandle UNU } else { - res = clientResponse->result; - OIC_LOG_V(ERROR, TAG, "OwnerUuidHandler : Unexpected result %d", res); + if (((OIC_MANUFACTURER_CERTIFICATE == otmCtx->selectedDeviceInfo->doxm->oxmSel) || + (OIC_CON_MFG_CERT == otmCtx->selectedDeviceInfo->doxm->oxmSel)) && + OC_STACK_NOT_ACCEPTABLE == clientResponse->result) + { + res = OC_STACK_USER_DENIED_REQ; + OIC_LOG_V(ERROR, TAG, + "OwnerUuidUpdateHandler : Denied Request(%d)", res); + } + else if (OC_STACK_GATEWAY_TIMEOUT == clientResponse->result) + { + res = clientResponse->result; + OIC_LOG_V(ERROR, TAG, + "OwnerUuidUpdateHandler : Timeout:No Response Received(%d)", res); + } + else + { + res = clientResponse->result; + OIC_LOG_V(ERROR, TAG, "OwnerUuidUpdateHandler : Unexpected result(%d)", res); + } SetResult(otmCtx, res); } @@ -624,6 +1136,49 @@ exit: return OC_STACK_DELETE_TRANSACTION; } +/* + * Invokes Callback to load Random PIN + */ +void *LoadRandomPin(void *ctx) +{ + OIC_LOG_V(DEBUG, TAG, "IN %s", __func__); + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + OCStackResult res = OC_STACK_ERROR; + res = otmCtx->otmCallback.loadSecretCB(otmCtx); + + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "%s : Failed to load secret", __func__); + SetResult(otmCtx, res); + OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__); + return NULL; + } + + //Save the current context instance to use on the dtls handshake callback + if(OC_STACK_OK != AddOTMContext(otmCtx, + otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort)) + { + OIC_LOG_V(ERROR, TAG, "%s : Failed to add OTM Context into OTM List.", __func__); + SetResult(otmCtx, res); + OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__); + return NULL; + } + + //Try DTLS handshake to generate secure session + if(otmCtx->otmCallback.createSecureSessionCB) + { + res = otmCtx->otmCallback.createSecureSessionCB(otmCtx); + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "%s : Failed to create DTLS session", __func__); + SetResult(otmCtx, res); + } + } + OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__); + return NULL; +} + /** * Response handler for update operation mode. * @@ -642,36 +1197,60 @@ static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle VERIFY_NON_NULL(TAG, ctx, WARNING); OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; (void) UNUSED; - if (OC_STACK_OK == clientResponse->result) + if (OC_STACK_RESOURCE_CHANGED == clientResponse->result) { OCStackResult res = OC_STACK_ERROR; - OicSecOxm_t selOxm = otmCtx->selectedDeviceInfo->doxm->oxmSel; + //DTLS Handshake //Load secret for temporal secure session. - if(g_OTMDatas[selOxm].loadSecretCB) + if(otmCtx->otmCallback.loadSecretCB) { - res = g_OTMDatas[selOxm].loadSecretCB(otmCtx); - if(OC_STACK_OK != res) + if (OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel) { - OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret"); - SetResult(otmCtx, res); - return OC_STACK_DELETE_TRANSACTION; + pthread_t p_thread; + int thr_result; + thr_result = pthread_create(&p_thread, NULL, LoadRandomPin, (void *) otmCtx); + if (0 != thr_result) + { + OIC_LOG_V(ERROR, TAG, "pthread_create Error with code %d", thr_result); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } + OIC_LOG(INFO, TAG, "Random Pin loadSecretCB Thread Created"); } - } + else + { + res = otmCtx->otmCallback.loadSecretCB(otmCtx); + if(OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret"); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } - //It will be used in handshake event handler - g_otmCtx = otmCtx; + //Save the current context instance to use on the dtls handshake callback + if(OC_STACK_OK != AddOTMContext(otmCtx, + otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort)) + { + OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to add OTM Context into OTM List."); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } - //Try DTLS handshake to generate secure session - if(g_OTMDatas[selOxm].createSecureSessionCB) - { - res = g_OTMDatas[selOxm].createSecureSessionCB(otmCtx); - if(OC_STACK_OK != res) - { - OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session"); - SetResult(otmCtx, res); - return OC_STACK_DELETE_TRANSACTION; + //Try DTLS handshake to generate secure session + if(otmCtx->otmCallback.createSecureSessionCB) + { + res = otmCtx->otmCallback.createSecureSessionCB(otmCtx); + if(OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session"); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } + } } } } @@ -706,16 +1285,63 @@ static OCStackApplicationResult OwnerCredentialHandler(void *ctx, OCDoHandle UNU (void)UNUSED; OCStackResult res = OC_STACK_OK; OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; - if(OC_STACK_RESOURCE_CREATED == clientResponse->result) + if(OC_STACK_RESOURCE_CHANGED == clientResponse->result) { if(otmCtx && otmCtx->selectedDeviceInfo) { - //PUT /oic/sec/doxm [{ ..., "owned":"TRUE" }] - res = PutOwnershipInformation(otmCtx); - if(OC_STACK_OK != res) + //Close the temporal secure session to verify the owner credential + CAEndpoint_t* endpoint = (CAEndpoint_t *)&otmCtx->selectedDeviceInfo->endpoint; + endpoint->port = otmCtx->selectedDeviceInfo->securePort; + CAResult_t caResult = CA_STATUS_OK; + caResult = CAcloseSslConnection(endpoint); + + if(CA_STATUS_OK != caResult) + { + OIC_LOG(ERROR, TAG, "Failed to close DTLS session"); + SetResult(otmCtx, caResult); + return OC_STACK_DELETE_TRANSACTION; + } + + /** + * If we select NULL cipher, + * client will select appropriate cipher suite according to server's cipher-suite list. + */ + // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */ + caResult = CASelectCipherSuite(0xC037, endpoint->adapter); + if(CA_STATUS_OK != caResult) + { + OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL"); + SetResult(otmCtx, caResult); + return OC_STACK_DELETE_TRANSACTION; + } + + /** + * in case of random PIN based OxM, + * revert get_psk_info callback of tinyDTLS to use owner credential. + */ + if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel) + { + OicUuid_t emptyUuid = { .id={0}}; + SetUuidForPinBasedOxm(&emptyUuid); + + caResult = CAregisterPskCredentialsHandler(GetDtlsPskCredentials); + + if(CA_STATUS_OK != caResult) + { + OIC_LOG(ERROR, TAG, "Failed to revert DTLS credential handler."); + SetResult(otmCtx, OC_STACK_INVALID_CALLBACK); + return OC_STACK_DELETE_TRANSACTION; + } + } +#ifdef __WITH_TLS__ + otmCtx->selectedDeviceInfo->connType |= CT_FLAG_SECURE; +#endif + res = PostOwnerAcl(otmCtx); + if(OC_STACK_OK != res) { - OIC_LOG(ERROR, TAG, "Failed to put ownership information to new device"); + OIC_LOG(ERROR, TAG, "Failed to update owner ACL to new device"); SetResult(otmCtx, res); return OC_STACK_DELETE_TRANSACTION; } @@ -734,6 +1360,53 @@ exit: return OC_STACK_DELETE_TRANSACTION; } +/** + * Response handler for update owner ACL request. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult OwnerAclHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + VERIFY_NON_NULL(TAG, clientResponse, WARNING); + VERIFY_NON_NULL(TAG, ctx, WARNING); + + OIC_LOG(DEBUG, TAG, "IN OwnerAclHandler"); + (void)UNUSED; + OCStackResult res = OC_STACK_OK; + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; + + if(OC_STACK_RESOURCE_CHANGED == clientResponse->result) + { + if(otmCtx && otmCtx->selectedDeviceInfo) + { + //POST /oic/sec/doxm [{ ..., "owned":"TRUE" }] + res = PostOwnershipInformation(otmCtx); + if(OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "Failed to update ownership information to new device"); + SetResult(otmCtx, res); + } + } + } + else + { + res = clientResponse->result; + OIC_LOG_V(ERROR, TAG, "OwnerAclHandler : Unexpected result %d", res); + SetResult(otmCtx, res); + } + + OIC_LOG(DEBUG, TAG, "OUT OwnerAclHandler"); + +exit: + return OC_STACK_DELETE_TRANSACTION; +} + /** * Response handler for update owner information request. @@ -754,15 +1427,16 @@ static OCStackApplicationResult OwnershipInformationHandler(void *ctx, OCDoHandl (void)UNUSED; OCStackResult res = OC_STACK_OK; OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->ocDoHandle = NULL; - if(OC_STACK_OK == clientResponse->result) + if(OC_STACK_RESOURCE_CHANGED == clientResponse->result) { if(otmCtx && otmCtx->selectedDeviceInfo) { OIC_LOG(INFO, TAG, "Ownership transfer was successfully completed."); - OIC_LOG(INFO, TAG, "Start defualt ACL & commit-hash provisioning."); + OIC_LOG(INFO, TAG, "Set Ready for provisioning state ."); - res = PutProvisioningStatus(otmCtx); + res = PostProvisioningStatus(otmCtx); if(OC_STACK_OK != res) { OIC_LOG(ERROR, TAG, "Failed to update pstat"); @@ -800,17 +1474,30 @@ static OCStackApplicationResult ProvisioningStatusHandler(void *ctx, OCDoHandle VERIFY_NON_NULL(TAG, clientResponse, ERROR); VERIFY_NON_NULL(TAG, ctx, ERROR); - OTMContext_t* otmCtx = (OTMContext_t*)ctx; + OTMContext_t* otmCtx = (OTMContext_t*) ctx; + otmCtx->ocDoHandle = NULL; (void)UNUSED; - if(OC_STACK_OK == clientResponse->result) + OCStackResult res = OC_STACK_OK; + + if(OC_STACK_RESOURCE_CHANGED == clientResponse->result) { - OCStackResult res = FinalizeProvisioning(otmCtx); - if (OC_STACK_OK != res) - { - OIC_LOG_V(INFO, TAG, "Failed to finalize provisioning."); + if(otmCtx && otmCtx->selectedDeviceInfo) + { + OIC_LOG(INFO, TAG, "Device state is in Ready for Provisionig."); + + res = PostNormalOperationStatus(otmCtx); + if(OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "Failed to update pstat"); SetResult(otmCtx, res); - return OC_STACK_DELETE_TRANSACTION; - } + } + } + } + else + { + OIC_LOG_V(INFO, TAG, "Error occured in provisionDefaultACLCB :: %d\n", + clientResponse->result); + SetResult(otmCtx, clientResponse->result); } exit: @@ -819,7 +1506,7 @@ exit: } /** - * Callback handler of finalize provisioning. + * Response handler of update provisioning status to Ready for Normal.. * * @param[in] ctx ctx value passed to callback from calling function. * @param[in] UNUSED handle to an invocation @@ -827,20 +1514,24 @@ exit: * @return OC_STACK_DELETE_TRANSACTION to delete the transaction * and OC_STACK_KEEP_TRANSACTION to keep it. */ -static OCStackApplicationResult FinalizeProvisioningCB(void *ctx, OCDoHandle UNUSED, +static OCStackApplicationResult ReadyForNomalStatusHandler(void *ctx, OCDoHandle UNUSED, OCClientResponse *clientResponse) { - OIC_LOG_V(INFO, TAG, "IN ProvisionDefaultACLCB."); + OIC_LOG_V(INFO, TAG, "IN ReadyForNomalStatusHandler."); VERIFY_NON_NULL(TAG, clientResponse, ERROR); VERIFY_NON_NULL(TAG, ctx, ERROR); OTMContext_t* otmCtx = (OTMContext_t*) ctx; + otmCtx->ocDoHandle = NULL; (void)UNUSED; - if (OC_STACK_RESOURCE_CREATED == clientResponse->result) + if (OC_STACK_RESOURCE_CHANGED == clientResponse->result) { - OCStackResult res = PDMAddDevice(&otmCtx->selectedDeviceInfo->doxm->deviceID); + OIC_LOG(INFO, TAG, "Device state is in Ready for Normal Operation."); + OTMStop(&otmCtx->selectedDeviceInfo->doxm->deviceID); + OCStackResult res = PDMSetDeviceState(&otmCtx->selectedDeviceInfo->doxm->deviceID, + PDM_DEVICE_ACTIVE); if (OC_STACK_OK == res) { OIC_LOG_V(INFO, TAG, "Add device's UUID in PDM_DB"); @@ -858,13 +1549,15 @@ static OCStackApplicationResult FinalizeProvisioningCB(void *ctx, OCDoHandle UNU clientResponse->result); SetResult(otmCtx, clientResponse->result); } + exit: + OIC_LOG_V(INFO, TAG, "OUT ReadyForNomalStatusHandler."); return OC_STACK_DELETE_TRANSACTION; } -static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx) +static OCStackResult PostOwnerCredential(OTMContext_t* otmCtx) { - OIC_LOG(DEBUG, TAG, "IN PutOwnerCredential"); + OIC_LOG(DEBUG, TAG, "IN PostOwnerCredential"); if(!otmCtx || !otmCtx->selectedDeviceInfo) { @@ -880,7 +1573,7 @@ static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx) deviceInfo->connType, query, sizeof(query), OIC_RSRC_CRED_URI)) { - OIC_LOG(ERROR, TAG, "PutOwnerCredential : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostOwnerCredential : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); @@ -893,11 +1586,11 @@ static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx) //Generate owner credential for new device secPayload->base.type = PAYLOAD_TYPE_SECURITY; - OicSecCred_t* ownerCredential = - GetCredResourceData(&(deviceInfo->doxm->deviceID)); + const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID)); if(!ownerCredential) { OIC_LOG(ERROR, TAG, "Can not find OwnerPSK."); + OICFree(secPayload); return OC_STACK_NO_RESOURCE; } @@ -907,25 +1600,38 @@ static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx) OicSecCred_t newCredential; memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t)); newCredential.next = NULL; + + //Set subject ID as PT's ID memcpy(&(newCredential.subject), &credSubjectId, sizeof(OicUuid_t)); - //Send owner credential to new device : PUT /oic/sec/cred [ owner credential ] - secPayload->securityData = BinToCredJSON(&newCredential); - if (NULL == secPayload->securityData) + //Fill private data as empty string + newCredential.privateData.data = (uint8_t*)""; + newCredential.privateData.len = 0; + newCredential.privateData.encoding = ownerCredential->privateData.encoding; + + newCredential.publicData.data = NULL; + newCredential.publicData.len = 0; + newCredential.publicData.encoding = ownerCredential->publicData.encoding; + + int secureFlag = 0; + //Send owner credential to new device : POST /oic/sec/cred [ owner credential ] + if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData, + &secPayload->payloadSize, secureFlag)) { OICFree(secPayload); - OIC_LOG(ERROR, TAG, "Error while converting bin to json"); + OIC_LOG(ERROR, TAG, "Error while converting bin to cbor."); return OC_STACK_ERROR; } - OIC_LOG_V(DEBUG, TAG, "Payload : %s", secPayload->securityData); + OIC_LOG(DEBUG, TAG, "Cred Payload:"); + OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize); OCCallbackData cbData; cbData.cb = &OwnerCredentialHandler; cbData.context = (void *)otmCtx; cbData.cd = NULL; - OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, + OCStackResult res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, &deviceInfo->endpoint, (OCPayload*)secPayload, - deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0); + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); if (res != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); @@ -937,14 +1643,174 @@ static OCStackResult PutOwnerCredential(OTMContext_t* otmCtx) return OC_STACK_NO_RESOURCE; } - OIC_LOG(DEBUG, TAG, "OUT PutOwnerCredential"); + OIC_LOG(DEBUG, TAG, "OUT PostOwnerCredential"); + + return OC_STACK_OK; +} + +static OicSecAcl_t* GenerateOwnerAcl(const OicUuid_t* owner) +{ + OicSecAcl_t* ownerAcl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t)); + OicSecAce_t* ownerAce = (OicSecAce_t*)OICCalloc(1, sizeof(OicSecAce_t)); + OicSecRsrc_t* wildcardRsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t)); + if(NULL == ownerAcl || NULL == ownerAce || NULL == wildcardRsrc) + { + OIC_LOG(ERROR, TAG, "Failed to memory allocation"); + goto error; + } + LL_APPEND(ownerAcl->aces, ownerAce); + LL_APPEND(ownerAce->resources, wildcardRsrc); + + //Set resource owner as PT + memcpy(ownerAcl->rownerID.id, owner->id, sizeof(owner->id)); + + //PT has full permission. + ownerAce->permission = PERMISSION_FULL_CONTROL; + + //Set subject as PT's UUID + memcpy(ownerAce->subjectuuid.id, owner->id, sizeof(owner->id)); + + wildcardRsrc->href = OICStrdup(WILDCARD_RESOURCE_URI); + if(NULL == wildcardRsrc->href) + { + goto error; + } + + wildcardRsrc->interfaceLen = 1; + wildcardRsrc->interfaces = (char**)OICMalloc(wildcardRsrc->interfaceLen * sizeof(char*)); + if(NULL == wildcardRsrc->interfaces) + { + goto error; + } + wildcardRsrc->interfaces[0] = OICStrdup(WILDCARD_RESOURCE_URI); + if(NULL == wildcardRsrc->interfaces[0]) + { + goto error; + } + + wildcardRsrc->typeLen = 1; + wildcardRsrc->types = (char**)OICMalloc(wildcardRsrc->typeLen * sizeof(char*)); + if(NULL == wildcardRsrc->types) + { + goto error; + } + wildcardRsrc->types[0] = OICStrdup(WILDCARD_RESOURCE_URI); + if(NULL == wildcardRsrc->types[0]) + { + goto error; + } + + return ownerAcl; + +error: + //in case of memory allocation failed, each resource should be removed individually. + if(NULL == ownerAcl || NULL == ownerAce || NULL == wildcardRsrc) + { + OICFree(ownerAcl); + OICFree(ownerAce); + OICFree(wildcardRsrc); + } + else + { + DeleteACLList(ownerAcl); + } + return NULL; +} + +/** + * Function to update the owner ACL to new device. + * + * @param[in] otmCtx Context value of ownership transfer. + * @return OC_STACK_OK on success + */ +static OCStackResult PostOwnerAcl(OTMContext_t* otmCtx) +{ + OCStackResult res = OC_STACK_ERROR; + + OIC_LOG(DEBUG, TAG, "IN PostOwnerAcl"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + OIC_LOG(ERROR, TAG, "Invalid parameters"); + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; + char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0}; + OicSecAcl_t* ownerAcl = NULL; + + if(!PMGenerateQuery(true, + deviceInfo->endpoint.addr, deviceInfo->securePort, + deviceInfo->connType, + query, sizeof(query), OIC_RSRC_ACL_URI)) + { + OIC_LOG(ERROR, TAG, "Failed to generate query"); + return OC_STACK_ERROR; + } + OIC_LOG_V(DEBUG, TAG, "Query=%s", query); + + OicUuid_t ownerID; + res = GetDoxmDeviceID(&ownerID); + if(OC_STACK_OK != res) + { + OIC_LOG(ERROR, TAG, "Failed to generate owner ACL"); + return res; + } + + //Generate owner ACL for new device + ownerAcl = GenerateOwnerAcl(&ownerID); + if(NULL == ownerAcl) + { + OIC_LOG(ERROR, TAG, "Failed to generate owner ACL"); + return OC_STACK_NO_MEMORY; + } + + //Generate ACL payload + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OIC_LOG(ERROR, TAG, "Failed to memory allocation"); + res = OC_STACK_NO_MEMORY; + goto error; + } + + res = AclToCBORPayload(ownerAcl, &secPayload->securityData, &secPayload->payloadSize); + if (OC_STACK_OK != res) + { + OICFree(secPayload); + OIC_LOG(ERROR, TAG, "Error while converting bin to cbor."); + goto error; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + + OIC_LOG(DEBUG, TAG, "Owner ACL Payload:"); + OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize); + + //Send owner ACL to new device : POST /oic/sec/cred [ owner credential ] + OCCallbackData cbData; + cbData.cb = &OwnerAclHandler; + cbData.context = (void *)otmCtx; + cbData.cd = NULL; + res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, + &deviceInfo->endpoint, (OCPayload*)secPayload, + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); + if (res != OC_STACK_OK) + { + OIC_LOG(ERROR, TAG, "OCStack resource error"); + goto error; + } + + OIC_LOG(DEBUG, TAG, "OUT PostOwnerAcl"); + +error: + DeleteACLList(ownerAcl); return OC_STACK_OK; } -static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx) +static OCStackResult PostOwnerTransferModeToResource(OTMContext_t* otmCtx) { - OIC_LOG(DEBUG, TAG, "IN PutOwnerTransferModeToResource"); + OIC_LOG(DEBUG, TAG, "IN PostOwnerTransferModeToResource"); if(!otmCtx || !otmCtx->selectedDeviceInfo) { @@ -953,7 +1819,6 @@ static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx) } OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; - OicSecOxm_t selectedOxm = deviceInfo->doxm->oxmSel; char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0}; if(!PMGenerateQuery(false, @@ -961,22 +1826,25 @@ static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx) deviceInfo->connType, query, sizeof(query), OIC_RSRC_DOXM_URI)) { - OIC_LOG(ERROR, TAG, "PutOwnerTransferModeToResource : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostOwnerTransferModeToResource : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); if(!secPayload) { OIC_LOG(ERROR, TAG, "Failed to memory allocation"); return OC_STACK_NO_MEMORY; } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; - secPayload->securityData = g_OTMDatas[selectedOxm].createSelectOxmPayloadCB(otmCtx); - if (NULL == secPayload->securityData) + OCStackResult res = otmCtx->otmCallback.createSelectOxmPayloadCB(otmCtx, + &secPayload->securityData, &secPayload->payloadSize); + if (OC_STACK_OK != res && NULL == secPayload->securityData) { - OICFree(secPayload); - OIC_LOG(ERROR, TAG, "Error while converting bin to json"); + OCPayloadDestroy((OCPayload *)secPayload); + OIC_LOG(ERROR, TAG, "Error while converting bin to cbor"); return OC_STACK_ERROR; } @@ -984,15 +1852,15 @@ static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx) cbData.cb = &OwnerTransferModeHandler; cbData.context = (void *)otmCtx; cbData.cd = NULL; - OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, - &deviceInfo->endpoint, (OCPayload*)secPayload, - deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0); + res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, + &deviceInfo->endpoint, (OCPayload *)secPayload, + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); if (res != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); } - OIC_LOG(DEBUG, TAG, "OUT PutOwnerTransferModeToResource"); + OIC_LOG(DEBUG, TAG, "OUT PostOwnerTransferModeToResource"); return res; } @@ -1023,8 +1891,8 @@ static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx) cbData.cb = &ListMethodsHandler; cbData.context = (void *)otmCtx; cbData.cd = NULL; - OCStackResult res = OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, - deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0); + OCStackResult res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_GET, query, NULL, NULL, + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); if (res != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); @@ -1035,9 +1903,9 @@ static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx) return res; } -static OCStackResult PutOwnerUuid(OTMContext_t* otmCtx) +static OCStackResult PostOwnerUuid(OTMContext_t* otmCtx) { - OIC_LOG(DEBUG, TAG, "IN PutOwnerUuid"); + OIC_LOG(DEBUG, TAG, "IN PostOwnerUuid"); if(!otmCtx || !otmCtx->selectedDeviceInfo) { @@ -1052,12 +1920,12 @@ static OCStackResult PutOwnerUuid(OTMContext_t* otmCtx) deviceInfo->connType, query, sizeof(query), OIC_RSRC_DOXM_URI)) { - OIC_LOG(ERROR, TAG, "PutOwnershipInformation : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostOwnerUuid : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); - //PUT PT's uuid to new device + //Post PT's uuid to new device OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); if(!secPayload) { @@ -1065,36 +1933,36 @@ static OCStackResult PutOwnerUuid(OTMContext_t* otmCtx) return OC_STACK_NO_MEMORY; } secPayload->base.type = PAYLOAD_TYPE_SECURITY; - secPayload->securityData = - g_OTMDatas[deviceInfo->doxm->oxmSel].createOwnerTransferPayloadCB(otmCtx); - if (NULL == secPayload->securityData) + OCStackResult res = otmCtx->otmCallback.createOwnerTransferPayloadCB( + otmCtx, &secPayload->securityData, &secPayload->payloadSize); + if (OC_STACK_OK != res && NULL == secPayload->securityData) { - OICFree(secPayload); - OIC_LOG(ERROR, TAG, "Error while converting doxm bin to json"); + OCPayloadDestroy((OCPayload *)secPayload); + OIC_LOG(ERROR, TAG, "Error while converting doxm bin to cbor."); return OC_STACK_INVALID_PARAM; } - OIC_LOG_V(DEBUG, TAG, "Payload : %s", secPayload->securityData); + OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize); OCCallbackData cbData; cbData.cb = &OwnerUuidUpdateHandler; cbData.context = (void *)otmCtx; cbData.cd = NULL; - OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload, - deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0); + res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, 0, (OCPayload *)secPayload, + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); if (res != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); } - OIC_LOG(DEBUG, TAG, "OUT PutOwnerUuid"); + OIC_LOG(DEBUG, TAG, "OUT PostOwnerUuid"); return res; } -static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx) +static OCStackResult PostOwnershipInformation(OTMContext_t* otmCtx) { - OIC_LOG(DEBUG, TAG, "IN PutOwnershipInformation"); + OIC_LOG(DEBUG, TAG, "IN PostOwnershipInformation"); if(!otmCtx || !otmCtx->selectedDeviceInfo) { @@ -1109,49 +1977,51 @@ static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx) deviceInfo->connType, query, sizeof(query), OIC_RSRC_DOXM_URI)) { - OIC_LOG(ERROR, TAG, "PutOwnershipInformation : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostOwnershipInformation : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); //OwnershipInformationHandler - OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); - if(!secPayload) + OCSecurityPayload *secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if (!secPayload) { OIC_LOG(ERROR, TAG, "Failed to memory allocation"); return OC_STACK_NO_MEMORY; } otmCtx->selectedDeviceInfo->doxm->owned = true; - secPayload->securityData = BinToDoxmJSON(otmCtx->selectedDeviceInfo->doxm); - if (NULL == secPayload->securityData) + + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + OCStackResult res = DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, + &secPayload->securityData, &secPayload->payloadSize, true); + if (OC_STACK_OK != res && NULL == secPayload->securityData) { - OICFree(secPayload); + OCPayloadDestroy((OCPayload *)secPayload); OIC_LOG(ERROR, TAG, "Error while converting doxm bin to json"); return OC_STACK_INVALID_PARAM; } - secPayload->base.type = PAYLOAD_TYPE_SECURITY; OCCallbackData cbData; cbData.cb = &OwnershipInformationHandler; cbData.context = (void *)otmCtx; cbData.cd = NULL; - OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload, - deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0); + res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, 0, (OCPayload*)secPayload, + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); if (res != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); } - OIC_LOG(DEBUG, TAG, "OUT PutOwnershipInformation"); + OIC_LOG(DEBUG, TAG, "OUT PostOwnershipInformation"); return res; } -static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx) +static OCStackResult PostUpdateOperationMode(OTMContext_t* otmCtx) { - OIC_LOG(DEBUG, TAG, "IN PutUpdateOperationMode"); + OIC_LOG(DEBUG, TAG, "IN PostUpdateOperationMode"); if(!otmCtx || !otmCtx->selectedDeviceInfo) { @@ -1165,7 +2035,7 @@ static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx) deviceInfo->connType, query, sizeof(query), OIC_RSRC_PSTAT_URI)) { - OIC_LOG(ERROR, TAG, "PutUpdateOperationMode : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostUpdateOperationMode : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); @@ -1177,11 +2047,12 @@ static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx) return OC_STACK_NO_MEMORY; } secPayload->base.type = PAYLOAD_TYPE_SECURITY; - secPayload->securityData = BinToPstatJSON(deviceInfo->pstat); - if (NULL == secPayload->securityData) + OCStackResult res = PstatToCBORPayload(deviceInfo->pstat, &secPayload->securityData, + &secPayload->payloadSize, true); + if (OC_STACK_OK != res) { - OICFree(secPayload); - OIC_LOG(ERROR, TAG, "Error while converting pstat bin to json"); + OCPayloadDestroy((OCPayload *)secPayload); + OIC_LOG(ERROR, TAG, "Error while converting pstat to cbor."); return OC_STACK_INVALID_PARAM; } @@ -1189,55 +2060,275 @@ static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx) cbData.cb = &OperationModeUpdateHandler; cbData.context = (void *)otmCtx; cbData.cd = NULL; - OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload, - deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0); + res = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, 0, (OCPayload *)secPayload, + deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); if (res != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); } - OIC_LOG(DEBUG, TAG, "OUT PutUpdateOperationMode"); + OIC_LOG(DEBUG, TAG, "OUT PostUpdateOperationMode"); + + return res; +} + +static OCStackResult SetupPDM(const OCProvisionDev_t* selectedDevice) +{ + OIC_LOG_V(DEBUG, TAG, "IN %s", __func__); + + PdmDeviceState_t pdmState = PDM_DEVICE_UNKNOWN; + OCStackResult res = PDMGetDeviceState(&selectedDevice->doxm->deviceID, &pdmState); + if (OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Internal error in PDMGetDeviceState : %d", res); + return res; + } + + char* strUuid = NULL; + bool removeCredReq = false; + if (OC_STACK_OK != ConvertUuidToStr(&selectedDevice->doxm->deviceID, &strUuid)) + { + OIC_LOG(WARNING, TAG, "Failed to covert uuid to string"); + return OC_STACK_NO_MEMORY; + } + + if (PDM_DEVICE_UNKNOWN == pdmState && !selectedDevice->doxm->owned) + { + removeCredReq = true; + } + else if (PDM_DEVICE_ACTIVE == pdmState && !selectedDevice->doxm->owned) + { + OIC_LOG_V(WARNING, TAG, "Unowned device[%s] dectected from PDM.", strUuid); + OIC_LOG_V(WARNING, TAG, "[%s] will be removed from PDM.", strUuid); + res = PDMDeleteDevice(&selectedDevice->doxm->deviceID); + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Failed to remove [%s] information from PDM.", strUuid); + goto exit; + } + + removeCredReq = true; + } + + if (removeCredReq) + { + OIC_LOG_V(WARNING, TAG, "[%s]'s credential will be removed.", strUuid); + res = RemoveCredential(&selectedDevice->doxm->deviceID); + if (OC_STACK_RESOURCE_DELETED != res) + { + OIC_LOG_V(WARNING, TAG, "Can not find [%s]'s credential.", strUuid); + } + } + + //Checking duplication of Device ID. + bool isDuplicate = true; + res = PDMIsDuplicateDevice(&selectedDevice->doxm->deviceID, &isDuplicate); + if (OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Internal error in PDMIsDuplicateDevice : %d", res); + goto exit; + } + + if (isDuplicate) + { + char* strUuid = NULL; + res = ConvertUuidToStr(&selectedDevice->doxm->deviceID, &strUuid); + if (OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Failed to convert UUID to str : %d", res); + goto exit; + } + + if (PDM_DEVICE_STALE == pdmState) + { + OIC_LOG(INFO, TAG, "Detected duplicated UUID in stale status, " + "device status will revert back to initial status."); + res = PDMSetDeviceState(&selectedDevice->doxm->deviceID, PDM_DEVICE_INIT); + if (OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Internal error in PDMSetDeviceState : %d", res); + goto exit; + } + } + else if (PDM_DEVICE_INIT == pdmState) + { + OIC_LOG_V(ERROR, TAG, "[%s]'s ownership transfer process is already started.", strUuid); + OICFree(strUuid); + res = OC_STACK_DUPLICATE_REQUEST; + goto exit; + } + else + { + OIC_LOG(ERROR, TAG, "Unknow device status while OTM."); + OICFree(strUuid); + res = OC_STACK_ERROR; + goto exit; + } + } + else + { + res = PDMAddDevice(&selectedDevice->doxm->deviceID); + if (OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Internal error in PDMAddDevice : %d", res); + goto exit; + } + } +exit: + OICFree(strUuid); + OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__); return res; } static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice) { OIC_LOG(INFO, TAG, "IN StartOwnershipTransfer"); + OCStackResult res = OC_STACK_INVALID_PARAM; + OicUuid_t emptyOwner = {.id = {0} }; + + VERIFY_NON_NULL(TAG, selectedDevice, ERROR); + VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR); + OTMContext_t* otmCtx = (OTMContext_t*)ctx; otmCtx->selectedDeviceInfo = selectedDevice; - //Set to the lowest level OxM, and then find more higher level OxM. - OCStackResult res = SelectProvisioningMethod(selectedDevice->doxm->oxm, - selectedDevice->doxm->oxmLen, - &selectedDevice->doxm->oxmSel); + //If devowneruuid of selectedDevice is not emtry, PostOwnerUuid does not triggered in DTLSHandshakeCB + if (memcmp(&(selectedDevice->doxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0) + { + OIC_LOG(DEBUG, TAG, "Set devowneruuid of selectedDevice to empty for OwnershipTransfer"); + memcpy(&(selectedDevice->doxm->owner), &emptyOwner, sizeof(OicUuid_t)); + } + + OicUuid_t ownerUuid = {0}; + GetDoxmDevOwnerId(&ownerUuid); + + res = OTMStart(&selectedDevice->doxm->deviceID, &ownerUuid); if(OC_STACK_OK != res) { - OIC_LOG(ERROR, TAG, "Failed to select the provisioning method"); + if(OC_STACK_DUPLICATE_UUID == res) + { + return res; + } + OIC_LOG_V(ERROR, TAG, "%s OTMStart error : %d", __func__, res); + } + + //Setup PDM to perform the OTM, PDM will be cleanup if necessary. + res = SetupPDM(selectedDevice); + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "SetupPDM error : %d", res); SetResult(otmCtx, res); return res; } - OIC_LOG_V(DEBUG, TAG, "Selected provisoning method = %d", selectedDevice->doxm->oxmSel); - //Send Req: PUT /oic/sec/doxm [{..."OxmSel" :g_OTMDatas[Index of Selected OxM].OXMString,...}] - res = PutOwnerTransferModeToResource(otmCtx); + //Select the OxM to performing ownership transfer + res = OTMSelectOwnershipTransferMethod(selectedDevice->doxm->oxm, + selectedDevice->doxm->oxmLen, + &selectedDevice->doxm->oxmSel, + SUPER_OWNER); if(OC_STACK_OK != res) { - OIC_LOG(WARNING, TAG, "Failed to select the provisioning method"); + OIC_LOG_V(ERROR, TAG, "Failed to select the provisioning method : %d", res); SetResult(otmCtx, res); return res; } + OIC_LOG_V(DEBUG, TAG, "Selected provisioning method = %d", selectedDevice->doxm->oxmSel); + + res = OTMSetOTCallback(selectedDevice->doxm->oxmSel, &otmCtx->otmCallback); + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Error in OTMSetOTCallback : %d", res); + return res; + } - //Register DTLS event handler to catch the dtls event while handshake - if(CA_STATUS_OK != CARegisterDTLSHandshakeCallback(DTLSHandshakeCB)) + //Send Req: POST /oic/sec/doxm [{..."OxmSel" :g_OTMCbDatas[Index of Selected OxM].OXMString,...}] + res = PostOwnerTransferModeToResource(otmCtx); + if(OC_STACK_OK != res) { - OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register DTLS handshake callback."); + OIC_LOG_V(WARNING, TAG, "Failed to select the provisioning method : %d", res); + SetResult(otmCtx, res); + return res; } +#if defined(__WITH_DTLS__) || defined(__WITH_TLS__) + //Register TLS event handler to catch the tls event while handshake + if(CA_STATUS_OK != CAregisterSslHandshakeCallback(DTLSHandshakeCB)) + { + OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register TLS handshake callback."); + } +#endif // __WITH_DTLS__ or __WITH_TLS__ OIC_LOG(INFO, TAG, "OUT StartOwnershipTransfer"); +exit: return res; +} + +static OCStackResult StartCustomOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice,const OicSecOxm_t method) +{ + OIC_LOG(INFO, TAG, "IN StartOwnershipTransfer"); + OCStackResult res = OC_STACK_INVALID_PARAM; + VERIFY_NON_NULL(TAG, selectedDevice, ERROR); + VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR); + + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + otmCtx->selectedDeviceInfo = selectedDevice; + + OicUuid_t ownerUuid = {0}; + GetDoxmDevOwnerId(&ownerUuid); + + res = OTMStart(&selectedDevice->doxm->deviceID, &ownerUuid); + if(OC_STACK_OK != res) + { + if(OC_STACK_DUPLICATE_UUID == res) + { + return res; + } + OIC_LOG_V(ERROR, TAG, "%s OTMStart error : %d", __func__, res); + } + + //Setup PDM to perform the OTM, PDM will be cleanup if necessary. + res = SetupPDM(selectedDevice); + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "SetupPDM error : %d", res); + SetResult(otmCtx, res); + return res; + } + + //Select the OxM to performing ownership transfer + selectedDevice->doxm->oxmSel = method; + OIC_LOG_V(DEBUG, TAG, "Selected provisioning method = %d", selectedDevice->doxm->oxmSel); + + res = OTMSetOTCallback(selectedDevice->doxm->oxmSel, &otmCtx->otmCallback); + if(OC_STACK_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Error in OTMSetOTCallback : %d", res); + return res; + } + +#if defined(__WITH_DTLS__) || defined(__WITH_TLS__) + //Register TLS event handler, to catch the TLS handshake event + if(CA_STATUS_OK != CAregisterSslHandshakeCallback(DTLSHandshakeCB)) + { + OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register TLS handshake callback."); + } +#endif // __WITH_DTLS__ or __WITH_TLS__ + + //Send Req: POST /oic/sec/doxm [{..."OxmSel" :g_OTMCbDatas[Index of Selected OxM].OXMString,...}] + res = PostOwnerTransferModeToResource(otmCtx); + if(OC_STACK_OK != res) + { + OIC_LOG_V(WARNING, TAG, "Failed to select the provisioning method : %d", res); + SetResult(otmCtx, res); + return res; + } + + OIC_LOG(INFO, TAG, "OUT StartOwnershipTransfer"); + +exit: + return res; } OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxmType, OTMCallbackData_t* data) @@ -1255,16 +2346,65 @@ OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxmType, OTMCallba return OC_STACK_INVALID_PARAM; } - g_OTMDatas[oxmType].loadSecretCB= data->loadSecretCB; - g_OTMDatas[oxmType].createSecureSessionCB = data->createSecureSessionCB; - g_OTMDatas[oxmType].createSelectOxmPayloadCB = data->createSelectOxmPayloadCB; - g_OTMDatas[oxmType].createOwnerTransferPayloadCB = data->createOwnerTransferPayloadCB; + // TODO: Remove this API, Please see the jira ticket IOT-1484 OIC_LOG(DEBUG, TAG, "OUT OTMSetOwnerTransferCallbackData"); return OC_STACK_OK; } +OCStackResult OTMDoCustomOwnershipTransfer(void* ctx, + OCProvisionDev_t *selectedDevice, + OCProvisionResultCB resultCallback, + const OicSecOxm_t method) +{ + OIC_LOG(DEBUG, TAG, "IN OTMDoCustomOwnershipTransfer"); + + if (NULL == selectedDevice) + { + return OC_STACK_INVALID_PARAM; + } + if (NULL == resultCallback) + { + return OC_STACK_INVALID_CALLBACK; + } + + OTMContext_t* otmCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t)); + if(!otmCtx) + { + OIC_LOG(ERROR, TAG, "Failed to create OTM Context"); + return OC_STACK_NO_MEMORY; + } + + otmCtx->ctxResultCallback = resultCallback; + otmCtx->ctxHasError = false; + otmCtx->userCtx = ctx; + + //Setting number of selected device. + otmCtx->ctxResultArraySize = 1; + + otmCtx->ctxResultArray = + (OCProvisionResult_t*)OICCalloc(otmCtx->ctxResultArraySize, sizeof(OCProvisionResult_t)); + if(NULL == otmCtx->ctxResultArray) + { + OIC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Failed to memory allocation"); + OICFree(otmCtx); + return OC_STACK_NO_MEMORY; + } + + //Fill the device UUID for result array. + memcpy(otmCtx->ctxResultArray[0].deviceId.id, + selectedDevice->doxm->deviceID.id, + UUID_LENGTH); + otmCtx->ctxResultArray[0].res = OC_STACK_CONTINUE; + + OCStackResult res = StartCustomOwnershipTransfer(otmCtx, selectedDevice, method); + + OIC_LOG(DEBUG, TAG, "OUT OTMDoCustomOwnershipTransfer"); + + return res; +} + /** * NOTE : Unowned discovery should be done before performing OTMDoOwnershipTransfer */ @@ -1312,23 +2452,9 @@ OCStackResult OTMDoOwnershipTransfer(void* ctx, } pCurDev = selectedDevicelist; - OCStackResult res = OC_STACK_OK; //Fill the device UUID for result array. for(size_t devIdx = 0; devIdx < otmCtx->ctxResultArraySize; devIdx++) { - //Checking duplication of Device ID. - bool isDuplicate = true; - res = PDMIsDuplicateDevice(&pCurDev->doxm->deviceID, &isDuplicate); - if (OC_STACK_OK != res) - { - goto error; - } - if (isDuplicate) - { - OIC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Device ID is duplicated"); - res = OC_STACK_INVALID_PARAM; - goto error; - } memcpy(otmCtx->ctxResultArray[devIdx].deviceId.id, pCurDev->doxm->deviceID.id, UUID_LENGTH); @@ -1336,52 +2462,68 @@ OCStackResult OTMDoOwnershipTransfer(void* ctx, pCurDev = pCurDev->next; } - StartOwnershipTransfer(otmCtx, selectedDevicelist); + OCStackResult res = StartOwnershipTransfer(otmCtx, selectedDevicelist); OIC_LOG(DEBUG, TAG, "OUT OTMDoOwnershipTransfer"); - return OC_STACK_OK; -error: - OICFree(otmCtx->ctxResultArray); - OICFree(otmCtx); return res; - } -OCStackResult PutProvisioningStatus(OTMContext_t* otmCtx) +OCStackResult OTMSetOxmAllowStatus(const OicSecOxm_t oxm, const bool allowStatus) { - OIC_LOG(INFO, TAG, "IN PutProvisioningStatus"); + OIC_LOG_V(INFO, TAG, "IN %s : oxm=%d, allow status=%s", + __func__, oxm, (allowStatus ? "true" : "false")); - if(!otmCtx) +#ifdef MULTIPLE_OWNER + if(OIC_OXM_COUNT <= oxm && OIC_MV_JUST_WORKS != oxm && OIC_PRECONFIG_PIN != oxm && OIC_CON_MFG_CERT != oxm) +#else + if(OIC_OXM_COUNT <= oxm && OIC_MV_JUST_WORKS != oxm && OIC_CON_MFG_CERT != oxm) +#endif { - OIC_LOG(ERROR, TAG, "OTMContext is NULL"); return OC_STACK_INVALID_PARAM; } - if(!otmCtx->selectedDeviceInfo) + + OxmAllowTableIdx_t oxmIdx = GetOxmAllowTableIdx(oxm); + if(OXM_IDX_COUNT <= oxmIdx) { - OIC_LOG(ERROR, TAG, "Can't find device information in OTMContext"); - OICFree(otmCtx); + OIC_LOG(ERROR, TAG, "Invalid oxm index to access oxm allow table."); + return OC_STACK_ERROR; + } + g_OxmAllowStatus[oxmIdx] = (allowStatus ? ALLOWED_OXM : NOT_ALLOWED_OXM); + + OIC_LOG_V(INFO, TAG, "OUT %s", __func__); + + return OC_STACK_OK; +} + +OCStackResult PostProvisioningStatus(OTMContext_t* otmCtx) +{ + OIC_LOG(INFO, TAG, "IN PostProvisioningStatus"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + OIC_LOG(ERROR, TAG, "OTMContext is NULL"); return OC_STACK_INVALID_PARAM; } - otmCtx->selectedDeviceInfo->pstat->tm = NORMAL; - otmCtx->selectedDeviceInfo->pstat->cm = PROVISION_ACLS | PROVISION_CREDENTIALS | - SECURITY_MANAGEMENT_SERVICES | BOOTSTRAP_SERVICE; - OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); - if(!secPayload) + //Change the TAKE_OWNER bit of CM to 0. + otmCtx->selectedDeviceInfo->pstat->cm &= (~TAKE_OWNER); + + OCSecurityPayload *secPayload = (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload)); + if (!secPayload) { OIC_LOG(ERROR, TAG, "Failed to memory allocation"); return OC_STACK_NO_MEMORY; } secPayload->base.type = PAYLOAD_TYPE_SECURITY; - secPayload->securityData = BinToPstatJSON(otmCtx->selectedDeviceInfo->pstat); - if (NULL == secPayload->securityData) + if (OC_STACK_OK != PstatToCBORPayload(otmCtx->selectedDeviceInfo->pstat, + &secPayload->securityData, &secPayload->payloadSize, true)) { - OICFree(secPayload); - SetResult(otmCtx, OC_STACK_INVALID_JSON); + OCPayloadDestroy((OCPayload *)secPayload); return OC_STACK_INVALID_JSON; } - OIC_LOG_V(INFO, TAG, "Created payload for commit hash: %s",secPayload->securityData); + OIC_LOG(DEBUG, TAG, "Created payload for chage to Provisiong state"); + OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize); char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0}; if(!PMGenerateQuery(true, @@ -1390,7 +2532,7 @@ OCStackResult PutProvisioningStatus(OTMContext_t* otmCtx) otmCtx->selectedDeviceInfo->connType, query, sizeof(query), OIC_RSRC_PSTAT_URI)) { - OIC_LOG(ERROR, TAG, "PutProvisioningStatus : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostProvisioningStatus : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); @@ -1399,119 +2541,167 @@ OCStackResult PutProvisioningStatus(OTMContext_t* otmCtx) cbData.cb = &ProvisioningStatusHandler; cbData.context = (void*)otmCtx; cbData.cd = NULL; - OCStackResult ret = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload, + OCStackResult ret = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, 0, (OCPayload*)secPayload, otmCtx->selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); OIC_LOG_V(INFO, TAG, "OCDoResource returned: %d",ret); if (ret != OC_STACK_OK) { OIC_LOG(ERROR, TAG, "OCStack resource error"); - SetResult(otmCtx, ret); } - OIC_LOG(INFO, TAG, "OUT PutProvisioningStatus"); + OIC_LOG(INFO, TAG, "OUT PostProvisioningStatus"); return ret; } -OCStackResult FinalizeProvisioning(OTMContext_t* otmCtx) +OCStackResult PostNormalOperationStatus(OTMContext_t* otmCtx) { - OIC_LOG(INFO, TAG, "IN FinalizeProvisioning"); + OIC_LOG(INFO, TAG, "IN PostNormalOperationStatus"); - if(!otmCtx) + if(!otmCtx || !otmCtx->selectedDeviceInfo) { OIC_LOG(ERROR, TAG, "OTMContext is NULL"); return OC_STACK_INVALID_PARAM; } - if(!otmCtx->selectedDeviceInfo) - { - OIC_LOG(ERROR, TAG, "Can't find device information in OTMContext"); - OICFree(otmCtx); - return OC_STACK_INVALID_PARAM; - } - // Provision Default ACL to device - OicSecAcl_t defaultAcl = - { {.id={0}}, - 1, - NULL, - 0x001F, - 0, - NULL, - NULL, - 1, - NULL, - NULL, - }; - - OicUuid_t provTooldeviceID = {.id={0}}; - if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID)) - { - OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); - SetResult(otmCtx, OC_STACK_ERROR); - return OC_STACK_ERROR; - } - OIC_LOG(INFO, TAG, "Retieved deviceID"); - memcpy(defaultAcl.subject.id, provTooldeviceID.id, sizeof(defaultAcl.subject.id)); - char *wildCardResource = "*"; - defaultAcl.resources = &wildCardResource; - defaultAcl.owners = (OicUuid_t *) OICCalloc(1, UUID_LENGTH); - if(!defaultAcl.owners) - { - OIC_LOG(ERROR, TAG, "Failed to memory allocation for default ACL"); - SetResult(otmCtx, OC_STACK_NO_MEMORY); - return OC_STACK_NO_MEMORY; - } - memcpy(defaultAcl.owners->id, provTooldeviceID.id, UUID_LENGTH); - OIC_LOG(INFO, TAG, "Provisioning default ACL"); + //Set isop to true. + otmCtx->selectedDeviceInfo->pstat->isOp = true; - OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); - if(!secPayload) + OCSecurityPayload *secPayload = (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload)); + if (!secPayload) { OIC_LOG(ERROR, TAG, "Failed to memory allocation"); return OC_STACK_NO_MEMORY; } secPayload->base.type = PAYLOAD_TYPE_SECURITY; - secPayload->securityData = BinToAclJSON(&defaultAcl); - OICFree(defaultAcl.owners); - if(!secPayload->securityData) + if (OC_STACK_OK != PstatToCBORPayload(otmCtx->selectedDeviceInfo->pstat, + &secPayload->securityData, &secPayload->payloadSize, true)) { - OICFree(secPayload); - OIC_LOG(INFO, TAG, "FinalizeProvisioning : Failed to BinToAclJSON"); - SetResult(otmCtx, OC_STACK_ERROR); - return OC_STACK_ERROR; + OCPayloadDestroy((OCPayload *)secPayload); + return OC_STACK_INVALID_JSON; } - OIC_LOG_V(INFO, TAG, "Provisioning default ACL : %s",secPayload->securityData); + OIC_LOG(DEBUG, TAG, "Created payload for chage to Provisiong state"); + OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize); char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0}; if(!PMGenerateQuery(true, otmCtx->selectedDeviceInfo->endpoint.addr, otmCtx->selectedDeviceInfo->securePort, otmCtx->selectedDeviceInfo->connType, - query, sizeof(query), OIC_RSRC_ACL_URI)) + query, sizeof(query), OIC_RSRC_PSTAT_URI)) { - OIC_LOG(ERROR, TAG, "FinalizeProvisioning : Failed to generate query"); + OIC_LOG(ERROR, TAG, "PostNormalOperationStatus : Failed to generate query"); return OC_STACK_ERROR; } OIC_LOG_V(DEBUG, TAG, "Query=%s", query); - OIC_LOG_V(INFO, TAG, "Request URI for Provisioning default ACL : %s", query); - - OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL}; - cbData.cb = &FinalizeProvisioningCB; - cbData.context = (void *)otmCtx; + OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL}; + cbData.cb = &ReadyForNomalStatusHandler; + cbData.context = (void*)otmCtx; cbData.cd = NULL; - OCStackResult ret = OCDoResource(NULL, OC_REST_POST, query, - &otmCtx->selectedDeviceInfo->endpoint, (OCPayload*)secPayload, + OCStackResult ret = OCDoResource(&otmCtx->ocDoHandle, OC_REST_POST, query, 0, (OCPayload*)secPayload, otmCtx->selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0); - if (OC_STACK_OK != ret) + OIC_LOG_V(INFO, TAG, "OCDoResource returned: %d",ret); + if (ret != OC_STACK_OK) { - SetResult(otmCtx, ret); - return ret; + OIC_LOG(ERROR, TAG, "OCStack resource error"); } - OIC_LOG(INFO, TAG, "OUT FinalizeProvisioning"); + OIC_LOG(INFO, TAG, "OUT PostNormalOperationStatus"); return ret; +} + +OCStackResult ConfigSelfOwnership(void) +{ + OIC_LOG(INFO, TAG, "IN ConfigSelfOwnership"); + + bool isDeviceOwned = true; + if (OC_STACK_OK != GetDoxmIsOwned(&isDeviceOwned)) + { + OIC_LOG (ERROR, TAG, "Unable to retrieve doxm owned state"); + return OC_STACK_ERROR; + } + if( (true == isDeviceOwned) ||(true == GetPstatIsop()) ) + { + OIC_LOG(ERROR, TAG, "The state of device is not Ready for Ownership transfer."); + return OC_STACK_ERROR; + } + OicUuid_t deviceID = {.id={0}}; + if ( OC_STACK_OK != GetDoxmDeviceID(&deviceID) ) + { + OIC_LOG (ERROR, TAG, "Unable to retrieve doxm Device ID"); + return OC_STACK_ERROR; + } + OCStackResult ret = OC_STACK_OK; + //Update the pstat resource as Normal Operation. + ret = SetPstatSelfOwnership(&deviceID); + if(OC_STACK_OK != ret) + { + OIC_LOG (ERROR, TAG, "Unable to update pstat resource as Normal Operation"); + goto exit; + } + //Update the doxm resource as Normal Operation. + ret = SetDoxmSelfOwnership(&deviceID); + if(OC_STACK_OK != ret) + { + OIC_LOG (ERROR, TAG, "Unable to update doxm resource as Normal Operation"); + goto exit; + } + //Update default ACE of security resource to prevent anonymous user access. + ret = UpdateDefaultSecProvACE(); + if(OC_STACK_OK != ret) + { + OIC_LOG (ERROR, TAG, "Unable to update default ace in ConfigSelfOwnership"); + goto exit; + } + //Update the acl resource owner as owner device. + ret = SetAclRownerId(&deviceID); + if(OC_STACK_OK != ret) + { + OIC_LOG (ERROR, TAG, "Unable to update acl resource in ConfigSelfOwnership"); + goto exit; + } + //Update the cred resource owner as owner device. + ret = SetCredRownerId(&deviceID); + if(OC_STACK_OK != ret) + { + // Cred resouce may be empty in Ready for Ownership transfer state. + if (OC_STACK_NO_RESOURCE == ret) + { + OIC_LOG (INFO, TAG, "Cred resource is empty"); + ret = OC_STACK_OK; + goto exit; + } + OIC_LOG (ERROR, TAG, "Unable to update cred resource in ConfigSelfOwnership"); + } + +exit: + if(OC_STACK_OK != ret) + { + /* + * If some error is occured while configure self-ownership, + * ownership related resource should be revert back to initial status. + */ + ResetSecureResourceInPS(); + } + + return ret; } + +void OTMTerminate() +{ + OIC_LOG_V(DEBUG, TAG, "In %s", __func__); + DeleteOTMContextList(); + +#if defined(__WITH_DTLS__) || defined(__WITH_TLS__) + if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL)) + { + OIC_LOG(WARNING, TAG, "Failed to register (D)TLS handshake callback."); + } +#endif // __WITH_DTLS__ or __WITH_TLS__ + + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); +}