From: Woochul Shim Date: Fri, 11 Sep 2015 05:37:15 +0000 (+0900) Subject: Add OCUnlink / OCRemove API to Provisioning Manager X-Git-Tag: 1.0.0-RC1~2^2~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d71f5b30414dd362b6f0753ce83b63c359b2a6c5;p=contrib%2Fiotivity.git Add OCUnlink / OCRemove API to Provisioning Manager - Since security admin should revoke disclosed credential, these API give capability to security admin to manage symmetric key type credentials in his/her network. [Patch #3,#4] Fix wrong behavior of functions, Correct style, unittest Change-Id: I73f14c207511ce85d739da0504aa8c65259b11cf Signed-off-by: Woochul Shim Signed-off-by: Randeep Singh Signed-off-by: Woochul Shim Reviewed-on: https://gerrit.iotivity.org/gerrit/2407 Tested-by: jenkins-iotivity Reviewed-by: Sachin Agrawal --- diff --git a/resource/csdk/security/provisioning/include/internal/provisioningdatabasemanager.h b/resource/csdk/security/provisioning/include/internal/provisioningdatabasemanager.h index 13cd8a4..72d64cc 100644 --- a/resource/csdk/security/provisioning/include/internal/provisioningdatabasemanager.h +++ b/resource/csdk/security/provisioning/include/internal/provisioningdatabasemanager.h @@ -34,7 +34,7 @@ extern "C" { * * @param[in] dbPath file path of the sqlite3 db * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMInit(const char* dbPath); @@ -44,7 +44,7 @@ OCStackResult PDMInit(const char* dbPath); * * @param[in] uuidOfDevice information about the target device's uuid. * - * @return false when non-duplication and true when duplication or uuidOfDevicea is NULL . + * @return false when non-duplication and true when duplication or uuidOfDevicea is NULL . */ bool PDMIsDuplicateDevice(const OicUuid_t* uuidOfDevice); @@ -53,7 +53,7 @@ bool PDMIsDuplicateDevice(const OicUuid_t* uuidOfDevice); * * @param[in] uuidOfDevice information about the owned device's uuid. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMAddDevice(const OicUuid_t* uuidOfDevice); @@ -63,7 +63,7 @@ OCStackResult PDMAddDevice(const OicUuid_t* uuidOfDevice); * @param[in] uuidOfDevice1 DeviceID which is going to be linked with uuid of device 2. * @param[in] uuidOfDevice2 DeviceID which is going to be linked with uuid of device 1. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMLinkDevices(const OicUuid_t *uuidOfDevice1, const OicUuid_t *uuidOfDevice2); @@ -73,7 +73,7 @@ OCStackResult PDMLinkDevices(const OicUuid_t *uuidOfDevice1, const OicUuid_t *uu * @param[in] uuidOfDevice1 DeviceID which is going to be unlinked with uuid of device 2. * @param[in] uuidOfDevice2 DeviceID which is going to be unlinked with uuid of device 1. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMUnlinkDevices(const OicUuid_t *uuidOfDevice1, const OicUuid_t *uuidOfDevice2); @@ -82,7 +82,7 @@ OCStackResult PDMUnlinkDevices(const OicUuid_t *uuidOfDevice1, const OicUuid_t * * * @param[in] uuidOfDevice information about the owned device's uuid to be deleted. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMDeleteDevice(const OicUuid_t *uuidOfDevice); @@ -92,7 +92,7 @@ OCStackResult PDMDeleteDevice(const OicUuid_t *uuidOfDevice); * @param[out] uuidList information about the list of owned devices' uuids. * @param[out] numOfDevices total number of owned devices. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMGetOwnedDevices(OCUuidList_t** uuidList, size_t* numOfDevices); @@ -103,7 +103,7 @@ OCStackResult PDMGetOwnedDevices(OCUuidList_t** uuidList, size_t* numOfDevices); * @param[out] uuidList information about the list of linked devices' uuids. * @param[out] numOfDevices total number of linked devices. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMGetLinkedDevices(const OicUuid_t* uuidOfDevice, OCUuidList_t** uuidList, size_t* numOfDevices); @@ -114,7 +114,7 @@ OCStackResult PDMGetLinkedDevices(const OicUuid_t* uuidOfDevice, OCUuidList_t** * @param[in] uuidOfDevice1 first id of stale link. * @param[in] uuidOfDevice2 other id for stale link. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMSetLinkStale(const OicUuid_t* uuidOfDevice1, const OicUuid_t* uuidOfDevice2); @@ -126,7 +126,7 @@ OCStackResult PDMSetLinkStale(const OicUuid_t* uuidOfDevice1, const OicUuid_t* u * @param[out] staleDevices information about the list of "To be Removed" devices' uuid. * @param[out] numOfDevices total number of devices to be removed. * - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMGetToBeUnlinkedDevices(OCPairList_t** staleDevList, size_t* numOfDevices); @@ -138,10 +138,10 @@ OCStackResult PDMGetToBeUnlinkedDevices(OCPairList_t** staleDevList, size_t* num OCStackResult PDMClose(); /** - * This method is used by provisioning manager free memory allocated to OicUuidList lists. + * This method is used by provisioning manager free memory allocated to OCUuidList_t lists. * * @param[in] ptr start pointer of link list. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMDestoryOicUuidLinkList(OCUuidList_t* ptr); @@ -149,7 +149,7 @@ OCStackResult PDMDestoryOicUuidLinkList(OCUuidList_t* ptr); * This method is used by provisioning manager free memory allocated to Stalelist. * * @param[in] ptr start pointer of link list. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult PDMDestoryStaleLinkList(OCPairList_t* ptr); diff --git a/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h b/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h index 1ea7fd6..2fff7f7 100644 --- a/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h +++ b/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h @@ -37,7 +37,7 @@ extern "C" * @param[in] acl ACL to provision. * @param[in] resultCallback callback provided by API user, callback will be called when * provisioning request recieves a response from resource server. - * @return SP_SUCCESS in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl, OCProvisionResultCB resultCallback); @@ -50,12 +50,49 @@ OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceI @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned. * @param[in] resultCallback callback provided by API user, callback will be called when * provisioning request recieves a response from first resource server. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult SRPProvisionCredentials(void *ctx,OicSecCredType_t type, size_t keySize, const OCProvisionDev_t *pDev1, const OCProvisionDev_t *pDev2, OCProvisionResultCB resultCallback); + +/** + * Function to unlink devices. + * This function will remove the credential & relationship between the two devices. + * + * @param[in] ctx Application context would be returned in result callback + * @param[in] pTargetDev1 first device information to be unlinked. + * @param[in] pTargetDev2 second device information to be unlinked. + * @param[in] resultCallback callback provided by API user, callback will be called when + * device unlink is finished. + * when there is an error, this user callback is called immediately. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult SRPUnlinkDevices(void* ctx, + const OCProvisionDev_t* pTargetDev1, + const OCProvisionDev_t* pTargetDev2, + OCProvisionResultCB resultCallback); + +/* + * Function to device revocation. + * This function will remove credential of target device from all devices in subnet. + * + * @param[in] ctx Application context would be returned in result callback + * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds) + * @param[in] pTargetDev Device information to be revoked. + * @param[in] resultCallback callback provided by API user, callback will be called when + * credential revocation is finished. + * when there is an error, this user callback is called immediately. + * @return OC_STACK_OK in case of success and other value otherwise. + * If OC_STACK_OK is returned, the caller of this API should wait for callback. + * OC_STACK_CONTINUE means operation is success but no request is need to be initiated. + */ +OCStackResult SRPRemoveDevice(void* ctx, + unsigned short waitTimeForOwnedDeviceDiscovery, + const OCProvisionDev_t* pTargetDev, + OCProvisionResultCB resultCallback); + #ifdef __cplusplus } #endif diff --git a/resource/csdk/security/provisioning/include/ocprovisioningmanager.h b/resource/csdk/security/provisioning/include/ocprovisioningmanager.h index 10f3974..2acc7ac 100644 --- a/resource/csdk/security/provisioning/include/ocprovisioningmanager.h +++ b/resource/csdk/security/provisioning/include/ocprovisioningmanager.h @@ -70,7 +70,7 @@ OCStackResult OCDoOwnershipTransfer(void* ctx, * * @param[in] Ownership transfer method. * @param[in] Implementation of callback functions for owership transfer. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData); @@ -96,7 +96,7 @@ OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t ** * @param[in] acl ACL for device 2. If this is not required set NULL. * @param[in] resultCallback callback provided by API user, callback will be called when * provisioning request recieves a response from first resource server. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize, const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl, @@ -111,7 +111,7 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_ * @param[in] acl ACL to provision. * @param[in] resultCallback callback provided by API user, callback will be called when provisioning request recieves a response from resource server. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl, OCProvisionResultCB resultCallback); @@ -125,7 +125,7 @@ OCStackResult OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceIn @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. * @param[in] resultCallback callback provided by API user, callback will be called when * provisioning request recieves a response from first resource server. - * @return OC_STACK_OK in case of success and other value otherwise. + * @return OC_STACK_OK in case of success and other value otherwise. */ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize, const OCProvisionDev_t *pDev1, @@ -133,6 +133,40 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke OCProvisionResultCB resultCallback); /** + * Function to unlink devices. + * This function will remove the credential & relasionship between the two devices. + * + * @param[in] ctx Application context would be returned in result callback + * @param[in] pTargetDev1 fitst device information to be unlinked. + * @param[in] pTargetDev2 second device information to be unlinked. + * @param[in] resultCallback callback provided by API user, callback will be called when + * device unlink is finished. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCUnlinkDevices(void* ctx, + const OCProvisionDev_t* pTargetDev1, + const OCProvisionDev_t* pTargetDev2, + OCProvisionResultCB resultCallback); + +/** + * Function for device revocation + * This function will remove credential of target device from all devices in subnet. + * + * @param[in] ctx Application context would be returned in result callback + * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds) + * @param[in] pTargetDev Device information to be revoked. + * @param[in] resultCallback callback provided by API user, callback will be called when + * credential revocation is finished. + * @return OC_STACK_OK in case of success and other value otherwise. + * if OC_STACK_OK is returned, the caller of this API should wait for callback. + * OC_STACK_CONTINUE means operation is success but no need to wait for callback. + */ +OCStackResult OCRemoveDevice(void* ctx, + unsigned short waitTimeForOwnedDeviceDiscovery, + const OCProvisionDev_t* pTargetDev, + OCProvisionResultCB resultCallback); + +/** * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API. * * @param[in] pList Pointer to OCProvisionDev_t which should be deleted. diff --git a/resource/csdk/security/provisioning/include/pmutility.h b/resource/csdk/security/provisioning/include/pmutility.h index 5387c90..7bf7571 100644 --- a/resource/csdk/security/provisioning/include/pmutility.h +++ b/resource/csdk/security/provisioning/include/pmutility.h @@ -55,6 +55,25 @@ OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisi */ void PMDeleteDeviceList(OCProvisionDev_t *pList); +/** + * Timeout implementation for secure discovery. When performing secure discovery, + * we should wait a certain period of time for getting response of each devices. + * + * @param[in] waittime Timeout in seconds. + * @param[in] waitForStackResponse if true timeout function will call OCProcess while waiting. + * @return OC_STACK_OK on success otherwise error. + */ +OCStackResult PMTimeout(unsigned short waittime, bool waitForStackResponse); + +/** + * Function to clone OCProvisionDev_t + * + * @param[in] src pointer of OCProvisionDev_t to be copied. + * + * @return copied OCProvisionDev_t on success otherwise NULL. + */ +OCProvisionDev_t* PMCloneOCProvisionDev(const OCProvisionDev_t* src); + /** * Function to generate qurey for coap/coaps request. @@ -74,6 +93,14 @@ bool PMGenerateQuery(bool isSecure, OCConnectivityType connType, char* buffer, size_t bufferSize, const char* uri); +/** + * Function to print OCProvisionDev_t for debug purpose. + * + * @param[in] pDev Pointer to OCProvisionDev_t. It's information will be printed by OC_LOG_XX + * + */ +void PMPrintOCProvisionDev(const OCProvisionDev_t* pDev); + #ifdef __cplusplus } #endif diff --git a/resource/csdk/security/provisioning/src/ocprovisioningmanager.c b/resource/csdk/security/provisioning/src/ocprovisioningmanager.c index f3488f6..4a463ca 100644 --- a/resource/csdk/security/provisioning/src/ocprovisioningmanager.c +++ b/resource/csdk/security/provisioning/src/ocprovisioningmanager.c @@ -27,6 +27,7 @@ #include "logger.h" #include "secureresourceprovider.h" #include "provisioningdatabasemanager.h" +#include "credresource.h" #define TAG "OCPMAPI" @@ -175,6 +176,144 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke } +/* +* Function to unlink devices. +* This function will remove the credential & relationship between the two devices. +* +* @param[in] ctx Application context would be returned in result callback +* @param[in] pTargetDev1 first device information to be unlinked. +* @param[in] pTargetDev2 second device information to be unlinked. +* @param[in] resultCallback callback provided by API user, callback will be called when +* device unlink is finished. + * @return OC_STACK_OK in case of success and other value otherwise. +*/ +OCStackResult OCUnlinkDevices(void* ctx, + const OCProvisionDev_t* pTargetDev1, + const OCProvisionDev_t* pTargetDev2, + OCProvisionResultCB resultCallback) +{ + OC_LOG(INFO, TAG, "IN OCUnlinkDevices"); + OCUuidList_t* idList = NULL; + size_t numOfDev = 0; + + if (!pTargetDev1 || !pTargetDev2 || !resultCallback) + { + OC_LOG(ERROR, TAG, "OCUnlinkDevices : NULL parameters"); + return OC_STACK_INVALID_PARAM; + } + + // Get linked devices with the first device. + OCStackResult res = PDMGetLinkedDevices(&(pTargetDev1->doxm->deviceID), &idList, &numOfDev); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "OCUnlinkDevices : PDMgetOwnedDevices failed"); + goto error; + } + if (1 > numOfDev) + { + OC_LOG(DEBUG, TAG, "OCUnlinkDevices : Can not find linked devices"); + res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made + goto error; + } + + // Check the linked devices contains the second device. If yes send credential DELETE request. + OCUuidList_t* curDev = idList; + while (NULL != curDev) + { + if (memcmp(pTargetDev2->doxm->deviceID.id, curDev->dev.id, sizeof(curDev->dev.id)) == 0) + { + res = SRPUnlinkDevices(ctx, pTargetDev1, pTargetDev2, resultCallback); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "OCUnlinkDevices : Failed to unlink devices."); + } + goto error; + } + curDev = curDev->next; + } + OC_LOG(DEBUG, TAG, "No matched pair found from provisioning database"); + res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made + +error: + OC_LOG(INFO, TAG, "OUT OCUnlinkDevices"); + + PDMDestoryOicUuidLinkList(idList); + return res; +} + +/* +* Function to device revocation +* This function will remove credential of target device from all devices in subnet. +* +* @param[in] ctx Application context would be returned in result callback +* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds) +* @param[in] pTargetDev Device information to be revoked. +* @param[in] resultCallback callback provided by API user, callback will be called when +* credential revocation is finished. + * @return OC_STACK_OK in case of success and other value otherwise. +*/ +OCStackResult OCRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery, + const OCProvisionDev_t* pTargetDev, + OCProvisionResultCB resultCallback) +{ + OC_LOG(INFO, TAG, "IN OCRemoveDevice"); + OCStackResult res = OC_STACK_ERROR; + if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery) + { + OC_LOG(INFO, TAG, "OCRemoveDevice : Invalied parameters"); + return OC_STACK_INVALID_PARAM; + } + + // Send DELETE requests to linked devices + OCStackResult resReq = OC_STACK_ERROR; // Check that we have to wait callback or not. + resReq = SRPRemoveDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback); + if (OC_STACK_OK != resReq) + { + if (OC_STACK_CONTINUE == resReq) + { + OC_LOG(DEBUG, TAG, "OCRemoveDevice : Revoked device has no linked device except PT."); + } + else + { + OC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to invoke SRPRemoveDevice"); + res = resReq; + goto error; + } + } + + // Remove credential of revoked device from SVR database + const OicSecCred_t *cred = NULL; + cred = GetCredResourceData(&pTargetDev->doxm->deviceID); + if (cred == NULL) + { + OC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device."); + goto error; + } + + res = RemoveCredential(&cred->subject); + if (res != OC_STACK_RESOURCE_DELETED) + { + OC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential."); + goto error; + } + + // Remove device info from prvisioning database. + res = PDMDeleteDevice(&pTargetDev->doxm->deviceID); + if (res != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to delete device in PDM."); + goto error; + } + + // Check that we have to wait callback for DELETE request or not + res = resReq; + +error: + OC_LOG(INFO, TAG, "OUT OCRemoveDevice"); + return res; +} + + /** * Internal Function to update result in link result array. */ @@ -182,7 +321,7 @@ static void UpdateLinkResults(Linkdata_t *link, int device, OCStackResult stackr { OC_LOG_V(INFO,TAG,"value of link->currentCountResults is %d",link->currentCountResults); - if(1 == device) + if (1 == device) { memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev1->doxm->deviceID.id,UUID_LENGTH); } @@ -211,7 +350,7 @@ static void AclProv2CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool has OCProvisionResultCB resultCallback = link->resultCallback; - if(hasError) + if (hasError) { UpdateLinkResults(link, 2,arr[0].res); OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1"); @@ -246,7 +385,7 @@ static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool has Linkdata_t *link = (Linkdata_t*)ctx; OCProvisionResultCB resultCallback = link->resultCallback; - if(hasError) + if (hasError) { OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1"); UpdateLinkResults(link, 1, arr[0].res); @@ -336,7 +475,6 @@ static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bo OICFree(link->resArr); OICFree(link); } - } else { @@ -368,7 +506,7 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_ OCProvisionResultCB resultCallback) { - if(!pDev1 || !pDev2 || !resultCallback) + if (!pDev1 || !pDev2 || !resultCallback) { OC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters"); return OC_STACK_INVALID_PARAM; @@ -383,12 +521,12 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_ { ++noOfResults; } - if(NULL!=pDev2Acl) + if (NULL!=pDev2Acl) { ++noOfResults; } Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t)); - if(!link) + if (!link) { OC_LOG(ERROR, TAG, "Failed to memory allocation"); return OC_STACK_NO_MEMORY; diff --git a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c index cddbeb9..1c88e95 100644 --- a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c +++ b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c @@ -131,7 +131,7 @@ static const char* GetOxmString(OicSecOxm_t oxmType) * @param[in] supportedMethods Array of supported methods * @param[in] numberOfMethods number of supported methods * @param[out] selectedMethod Selected methods - * @return SP_SUCCESS on success + * @return OC_STACK_OK on success */ static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethods, size_t numberOfMethods, @@ -162,7 +162,7 @@ static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethod * * @param[in] selectedDeviceInfo selected device information to performing provisioning. * @param[out] selectedMode selected operation mode - * @return SP_SUCCESS on success + * @return OC_STACK_OK on success */ static void SelectOperationMode(const OCProvisionDev_t *selectedDeviceInfo, OicSecDpom_t *selectedMode) diff --git a/resource/csdk/security/provisioning/src/pmutility.c b/resource/csdk/security/provisioning/src/pmutility.c index 8019d2f..111c180 100644 --- a/resource/csdk/security/provisioning/src/pmutility.c +++ b/resource/csdk/security/provisioning/src/pmutility.c @@ -42,6 +42,8 @@ #include "pmtypes.h" #include "pmutility.h" +#include "srmutility.h" + #define TAG ("PM-UTILITY") typedef struct _DiscoveryInfo{ @@ -170,14 +172,73 @@ void PMDeleteDeviceList(OCProvisionDev_t *pDevicesList) } } +OCProvisionDev_t* PMCloneOCProvisionDev(const OCProvisionDev_t* src) +{ + OC_LOG(DEBUG, TAG, "IN PMCloneOCProvisionDev"); + + if (!src) + { + OC_LOG(ERROR, TAG, "PMCloneOCProvisionDev : Invalid parameter"); + return NULL; + } + + // TODO: Consider use VERIFY_NON_NULL instead of if ( null check ) { goto exit; } + OCProvisionDev_t* newDev = (OCProvisionDev_t*)OICCalloc(1, sizeof(OCProvisionDev_t)); + VERIFY_NON_NULL(TAG, newDev, ERROR); + + memcpy(&newDev->endpoint, &src->endpoint, sizeof(OCDevAddr)); + + if (src->pstat) + { + newDev->pstat= (OicSecPstat_t*)OICCalloc(1, sizeof(OicSecPstat_t)); + VERIFY_NON_NULL(TAG, newDev->pstat, ERROR); + + memcpy(newDev->pstat, src->pstat, sizeof(OicSecPstat_t)); + // We have to assign NULL for not necessary information to prevent memory corruption. + newDev->pstat->sm = NULL; + } + + if (src->doxm) + { + newDev->doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t)); + VERIFY_NON_NULL(TAG, newDev->doxm, ERROR); + + memcpy(newDev->doxm, src->doxm, sizeof(OicSecDoxm_t)); + // We have to assign NULL for not necessary information to prevent memory corruption. + newDev->doxm->oxmType = NULL; + newDev->doxm->oxm = NULL; + } + + newDev->securePort = src->securePort; + //TODO: Below comment line should be activated after 2333 change is merged + //newDev->devStatus = src->devStatus; + newDev->connType = src->connType; + newDev->next = NULL; + + OC_LOG(DEBUG, TAG, "OUT PMCloneOCProvisionDev"); + + return newDev; + +exit: + OC_LOG(ERROR, TAG, "PMCloneOCProvisionDev : Failed to allocate memory"); + if (newDev) + { + OICFree(newDev->pstat); + OICFree(newDev->doxm); + OICFree(newDev); + } + return NULL; +} + /** * Timeout implementation for secure discovery. When performing secure discovery, * we should wait a certain period of time for getting response of each devices. * * @param[in] waittime Timeout in seconds. + * @param[in] waitForStackResponse if true timeout function will call OCProcess while waiting. * @return OC_STACK_OK on success otherwise error. */ -OCStackResult PMTimeout(unsigned short waittime) +OCStackResult PMTimeout(unsigned short waittime, bool waitForStackResponse) { struct timespec startTime = {.tv_sec=0, .tv_nsec=0}; struct timespec currTime = {.tv_sec=0, .tv_nsec=0}; @@ -208,9 +269,11 @@ OCStackResult PMTimeout(unsigned short waittime) { return OC_STACK_OK; } - res = OCProcess(); + if (waitForStackResponse) + { + res = OCProcess(); + } } - return res; } @@ -558,7 +621,7 @@ OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisi } //Waiting for each response. - res = PMTimeout(waittime); + res = PMTimeout(waittime, true); if(OC_STACK_OK != res) { OC_LOG(ERROR, TAG, "Failed to wait response for secure discovery."); @@ -571,3 +634,25 @@ exit: OICFree(pDInfo); return res; } + +/** + * Function to print OCProvisionDev_t for debug purpose. + * + * @param[in] pDev Pointer to OCProvisionDev_t. It's information will be printed by OC_LOG_XX + * + */ +void PMPrintOCProvisionDev(const OCProvisionDev_t* pDev) +{ + if (pDev) + { + OC_LOG(DEBUG, TAG, "+++++ OCProvisionDev_t Information +++++"); + OC_LOG_V(DEBUG, TAG, "IP %s", pDev->endpoint.addr); + OC_LOG_V(DEBUG, TAG, "PORT %d", pDev->endpoint.port); + OC_LOG_V(DEBUG, TAG, "S-PORT %d", pDev->securePort); + OC_LOG(DEBUG, TAG, "++++++++++++++++++++++++++++++++++++++++"); + } + else + { + OC_LOG(DEBUG, TAG, "+++++ OCProvisionDev_t is NULL +++++"); + } +} diff --git a/resource/csdk/security/provisioning/src/provisioningdatabasemanager.c b/resource/csdk/security/provisioning/src/provisioningdatabasemanager.c index e27fdba..5cfd94a 100644 --- a/resource/csdk/security/provisioning/src/provisioningdatabasemanager.c +++ b/resource/csdk/security/provisioning/src/provisioningdatabasemanager.c @@ -233,9 +233,11 @@ static OCStackResult getIdForUUID(const OicUuid_t *UUID , int *id) int tempId = sqlite3_column_int(stmt, PDM_FIRST_INDEX); OC_LOG_V(DEBUG, TAG, "ID is %d", tempId); *id = tempId; + sqlite3_finalize(stmt); + return OC_STACK_OK; } sqlite3_finalize(stmt); - return OC_STACK_OK; + return OC_STACK_INVALID_PARAM; } /** @@ -447,7 +449,7 @@ static OCStackResult updateLinkState(int id1, int id2, int state) { OC_LOG_V(ERROR, TAG, "Error message: %s", sqlite3_errmsg(g_db)); sqlite3_finalize(stmt); - return OC_STACK_OK; + return OC_STACK_ERROR; } sqlite3_finalize(stmt); return OC_STACK_OK; diff --git a/resource/csdk/security/provisioning/src/secureresourceprovider.c b/resource/csdk/security/provisioning/src/secureresourceprovider.c index 7fb451b..a153e06 100644 --- a/resource/csdk/security/provisioning/src/secureresourceprovider.c +++ b/resource/csdk/security/provisioning/src/secureresourceprovider.c @@ -37,8 +37,9 @@ #include "pmtypes.h" #include "pmutility.h" #include "provisioningdatabasemanager.h" +#include "base64.h" +#include "utlist.h" -#define SRP_MAX_URI_LENGTH 512 #define TAG "SRPAPI" /** @@ -84,6 +85,39 @@ struct ACLData int numOfResults; /**< Number of results in result array.**/ }; +// Enum type index for unlink callback. +typedef enum { + IDX_FIRST_DEVICE_RES = 0, // index for resulf of the first device + IDX_SECOND_DEVICE_RES, // index for result of the second device + IDX_DB_UPDATE_RES // index for result of updating provisioning database. +} IdxUnlinkRes_t; + +// Structure to carry unlink APIs data to callback. +typedef struct UnlinkData UnlinkData_t; +struct UnlinkData { + void *ctx; + OCProvisionDev_t* unlinkDev; /**< Pointer to OCProvisionDev_t to be unlinked.**/ + OCProvisionResult_t* unlinkRes; /**< Result array.**/ + OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/ + int numOfResults; /**< Number of results in result array.**/ +}; + +//Example of DELETE cred request -> coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID) +const char * SRP_FORM_DELETE_CREDENTIAL = "coaps://[%s]:%d%s?%s=%s"; + +// Structure to carry remove APIs data to callback. +typedef struct RemoveData RemoveData_t; +struct RemoveData { + void *ctx; + OCProvisionDev_t* revokeTargetDev; /**< Device which is going to be revoked..**/ + OCProvisionDev_t* linkedDevList; /**< A list of devices which have invalid credential.**/ + OCProvisionResult_t* removeRes; /**< Result array.**/ + OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/ + size_t numOfResults; /**< Number of results in result array.**/ + size_t sizeOfResArray; + bool hasError; +}; + /** * Function prototype */ @@ -141,7 +175,7 @@ static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNU &credData->deviceInfo2->doxm->deviceID); if (OC_STACK_OK != res) { - OC_LOG(ERROR, TAG, "Error occured on PDMlinkDevices"); + OC_LOG(ERROR, TAG, "Error occured on PDMLinkDevices"); return OC_STACK_DELETE_TRANSACTION; } OC_LOG(INFO, TAG, "Link created successfully"); @@ -504,3 +538,603 @@ OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceI VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR); return OC_STACK_OK; } + +static void DeleteUnlinkData_t(UnlinkData_t *unlinkData) +{ + if (unlinkData) + { + OICFree(unlinkData->unlinkDev); + OICFree(unlinkData->unlinkRes); + OICFree(unlinkData); + } +} + +static void registerResultForUnlinkDevices(UnlinkData_t *unlinkData, OCStackResult stackresult, + IdxUnlinkRes_t idx) +{ + if (NULL != unlinkData) + { + OC_LOG_V(INFO, TAG, "Inside registerResultForUnlinkDevices unlinkData->numOfResults is %d\n", + unlinkData->numOfResults); + OC_LOG_V(INFO, TAG, "Stack result :: %d", stackresult); + + OicUuid_t *pUuid = &unlinkData->unlinkRes[(unlinkData->numOfResults)].deviceId; + + // Set result in the result array according to the position (devNum). + if (idx != IDX_DB_UPDATE_RES) + { + memcpy(pUuid->id, unlinkData->unlinkDev[idx].doxm->deviceID.id, sizeof(pUuid->id)); + } + else + { // When deivce ID is 000... this means it's the result of database update. + memset(pUuid->id, 0, sizeof(pUuid->id)); + } + unlinkData->unlinkRes[(unlinkData->numOfResults)].res = stackresult; + ++(unlinkData->numOfResults); + OC_LOG (INFO, TAG, "Out registerResultForUnlinkDevices"); + } +} + +static OCStackResult SendDeleteCredentialRequest(void* ctx, + OCClientResponseHandler respHandler, + const OCProvisionDev_t* revokedDev, + const OCProvisionDev_t* destDev) +{ + OC_LOG(DEBUG, TAG, "IN SendDeleteCredentialRequest"); + + if (NULL == ctx || NULL == respHandler || NULL == revokedDev || NULL == destDev) + { + return OC_STACK_INVALID_PARAM; + } + + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(revokedDev->doxm->deviceID.id)) + 1] = {}; + uint32_t base64Len = 0; + if (B64_OK != b64Encode(revokedDev->doxm->deviceID.id, sizeof(revokedDev->doxm->deviceID.id), + base64Buff, sizeof(base64Buff), &base64Len)) + { + OC_LOG(ERROR, TAG, "SendDeleteCredentialRequest : Failed to base64 encoding"); + return OC_STACK_ERROR; + } + + char reqBuf[MAX_REQUEST_LENGTH] = {0}; + int snRet = 0; + //coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID) + snRet = snprintf(reqBuf, sizeof(reqBuf), SRP_FORM_DELETE_CREDENTIAL, destDev->endpoint.addr, + destDev->securePort, OIC_RSRC_CRED_URI, OIC_JSON_SUBJECT_NAME, base64Buff); + if (snRet < 0 || snRet >= sizeof(reqBuf)) + { + OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error (snprintf) %d\n", snRet); + OC_LOG(ERROR, TAG, " Truncated or error"); + return OC_STACK_ERROR; + } + OCCallbackData cbData; + memset(&cbData, 0, sizeof(cbData)); + cbData.context = ctx; + cbData.cb = respHandler; + cbData.cd = NULL; + OC_LOG_V(INFO, TAG, "URI: %s",reqBuf); + + OC_LOG(DEBUG, TAG, "Sending remove credential request to resource server"); + + OCStackResult ret = OCDoResource(NULL, OC_REST_DELETE, reqBuf, + &destDev->endpoint, NULL, + CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0); + if (OC_STACK_OK != ret) + { + OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error in OCDoResource %d", ret); + } + OC_LOG(DEBUG, TAG, "OUT SendDeleteCredentialRequest"); + + return ret; +} + +/** + * Callback handler of unlink second device. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] handle 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 SRPUnlinkDevice2CB(void *unlinkCtx, OCDoHandle handle, + OCClientResponse *clientResponse) +{ + (void) handle; + OC_LOG(DEBUG, TAG, "IN SRPUnlinkDevice2CB"); + VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION); + UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx; + + if (clientResponse) + { + OC_LOG(DEBUG, TAG, "Valid client response for device 2"); + registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_SECOND_DEVICE_RES); + + if (OC_STACK_RESOURCE_DELETED == clientResponse->result) + { + OC_LOG(DEBUG, TAG, "Credential of device2 revoked"); + } + else + { + OC_LOG(ERROR, TAG, "Unable to delete credential information from device 2"); + unlinkData->resultCallback(unlinkData->ctx, + unlinkData->numOfResults, unlinkData->unlinkRes, true); + goto error; + } + } + else + { + registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE, + IDX_SECOND_DEVICE_RES); + unlinkData->resultCallback(unlinkData->ctx, + unlinkData->numOfResults, unlinkData->unlinkRes, true); + OC_LOG(ERROR, TAG, "SRPUnlinkDevice2CB received Null clientResponse"); + goto error; + } + + //Update provisioning DB when succes case. + if (OC_STACK_OK != PDMUnlinkDevices(&unlinkData->unlinkDev[0].doxm->deviceID, + &unlinkData->unlinkDev[1].doxm->deviceID)) + { + OC_LOG(FATAL, TAG, "All requests are successfully done but update provisioning DB FAILED."); + registerResultForUnlinkDevices(unlinkData, OC_STACK_INCONSISTENT_DB, IDX_DB_UPDATE_RES); + unlinkData->resultCallback(unlinkData->ctx, + unlinkData->numOfResults, unlinkData->unlinkRes, true); + goto error; + } + unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, unlinkData->unlinkRes, + false); + +error: + DeleteUnlinkData_t(unlinkData); + OC_LOG(DEBUG, TAG, "OUT SRPUnlinkDevice2CB"); + return OC_STACK_DELETE_TRANSACTION; + +} + +/** + * Callback handler of unlink first device. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] handle 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 SRPUnlinkDevice1CB(void *unlinkCtx, OCDoHandle handle, + OCClientResponse *clientResponse) +{ + OC_LOG_V(INFO, TAG, "Inside SRPUnlinkDevice1CB "); + VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION); + UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx; + (void) handle; + + if (clientResponse) + { + OC_LOG(DEBUG, TAG, "Valid client response for device 1"); + registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_FIRST_DEVICE_RES); + + if (OC_STACK_RESOURCE_DELETED == clientResponse->result) + { + OC_LOG(DEBUG, TAG, "Credential of device 1 is revoked"); + + // Second revocation request to second device. + OCStackResult res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice2CB, + &unlinkData->unlinkDev[0], + &unlinkData->unlinkDev[1] /*Dest*/); + OC_LOG_V(DEBUG, TAG, "Credential revocation request device 2, result :: %d",res); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Error while sending revocation request for device 2"); + registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE, + IDX_SECOND_DEVICE_RES); + unlinkData->resultCallback(unlinkData->ctx, + unlinkData->numOfResults, unlinkData->unlinkRes, true); + goto error; + } + else + { + OC_LOG(DEBUG, TAG, "Request for credential revocation successfully sent"); + return OC_STACK_DELETE_TRANSACTION; + } + } + else + { + OC_LOG(ERROR, TAG, "Unable to delete credential information from device 1"); + + unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, + unlinkData->unlinkRes, true); + goto error; + } + } + else + { + OC_LOG(DEBUG, TAG, "Invalid response from server"); + registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE, + IDX_FIRST_DEVICE_RES ); + unlinkData->resultCallback(unlinkData->ctx, + unlinkData->numOfResults, unlinkData->unlinkRes, + true); + OC_LOG(ERROR, TAG, "SRPUnlinkDevice1CB received Null clientResponse"); + } + +error: + OC_LOG_V(INFO, TAG, "Out SRPUnlinkDevice1CB"); + DeleteUnlinkData_t(unlinkData); + return OC_STACK_DELETE_TRANSACTION; +} + +/* +* Function to unlink devices. +* This function will remove the credential & relationship between the two devices. +* +* @param[in] ctx Application context would be returned in result callback +* @param[in] pTargetDev1 first device information to be unlinked. +* @param[in] pTargetDev2 second device information to be unlinked. +* @param[in] resultCallback callback provided by API user, callback will be called when +* device unlink is finished. + * @return OC_STACK_OK in case of success and other value otherwise. +*/ +OCStackResult SRPUnlinkDevices(void* ctx, + const OCProvisionDev_t* pTargetDev1, + const OCProvisionDev_t* pTargetDev2, + OCProvisionResultCB resultCallback) +{ + OC_LOG(INFO, TAG, "IN SRPUnlinkDevices"); + + if (!pTargetDev1 || !pTargetDev2 || !resultCallback) + { + OC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL parameters"); + return OC_STACK_INVALID_PARAM; + } + OC_LOG(INFO, TAG, "Unlinking following devices: "); + PMPrintOCProvisionDev(pTargetDev1); + PMPrintOCProvisionDev(pTargetDev2); + + // Mark the link status stale + OCStackResult res = PDMSetLinkStale(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID); + if (OC_STACK_OK != res) + { + OC_LOG(FATAL, TAG, "unable to update DB. Try again."); + return res; + } + + UnlinkData_t* unlinkData = (UnlinkData_t*)OICCalloc(1, sizeof(UnlinkData_t)); + VERIFY_NON_NULL(TAG, unlinkData, ERROR, OC_STACK_NO_MEMORY); + + //Initialize unlink data + unlinkData->ctx = ctx; + unlinkData->unlinkDev = (OCProvisionDev_t*)OICCalloc(2, sizeof(OCProvisionDev_t)); + if (NULL == unlinkData->unlinkDev) + { + OC_LOG(ERROR, TAG, "Memory allocation failed"); + res = OC_STACK_NO_MEMORY; + goto error; + } + + unlinkData->unlinkRes = (OCProvisionResult_t*)OICCalloc(3, sizeof(OCProvisionResult_t)); + if (NULL == unlinkData->unlinkRes) + { + OC_LOG(ERROR, TAG, "Memory allocation failed"); + res = OC_STACK_NO_MEMORY; + goto error; + } + + memcpy(&unlinkData->unlinkDev[0], pTargetDev1, sizeof(OCProvisionDev_t)); + memcpy(&unlinkData->unlinkDev[1], pTargetDev2, sizeof(OCProvisionDev_t)); + + unlinkData->numOfResults = 0; + unlinkData->resultCallback = resultCallback; + + res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice1CB, + &unlinkData->unlinkDev[1], &unlinkData->unlinkDev[0]); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "SRPUnlinkDevices : SendDeleteCredentialRequest failed"); + goto error; + } + + return res; + +error: + OC_LOG(INFO, TAG, "OUT SRPUnlinkDevices"); + DeleteUnlinkData_t(unlinkData); + return res; +} + +static void DeleteRemoveData_t(RemoveData_t* pRemoveData) +{ + if (pRemoveData) + { + OICFree(pRemoveData->revokeTargetDev); + OCDeleteDiscoveredDevices(pRemoveData->linkedDevList); + OICFree(pRemoveData->removeRes); + OICFree(pRemoveData); + } +} + +static void registerResultForRemoveDevice(RemoveData_t *removeData, OicUuid_t *pLinkedDevId, + OCStackResult stackresult, bool hasError) +{ + OC_LOG_V(INFO, TAG, "Inside registerResultForRemoveDevice removeData->numOfResults is %d\n", + removeData->numOfResults + 1); + if (pLinkedDevId) + { + memcpy(removeData->removeRes[(removeData->numOfResults)].deviceId.id, + &pLinkedDevId->id, sizeof(pLinkedDevId->id)); + } + else + { + memset(removeData->removeRes[(removeData->numOfResults)].deviceId.id, + 0, sizeof(pLinkedDevId->id) ); + } + removeData->removeRes[(removeData->numOfResults)].res = stackresult; + removeData->hasError = hasError; + ++(removeData->numOfResults); + + // If we get suffcient result from linked devices, we have to call user callback and do free + if (removeData->sizeOfResArray == removeData->numOfResults) + { + removeData->resultCallback(removeData->ctx, removeData->numOfResults, removeData->removeRes, + removeData->hasError); + DeleteRemoveData_t(removeData); + } + } + +/** + * Callback handler of unlink first device. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] handle 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 SRPRemoveDeviceCB(void *delDevCtx, OCDoHandle handle, + OCClientResponse *clientResponse) +{ + //Update the delete credential into delete device context + //Save the deleted status in delDevCtx + (void)handle; + OC_LOG_V(INFO, TAG, "Inside SRPRemoveDeviceCB."); + VERIFY_NON_NULL(TAG, delDevCtx, ERROR, OC_STACK_DELETE_TRANSACTION); + OCStackResult res = OC_STACK_ERROR; + + RemoveData_t* removeData = (RemoveData_t*)delDevCtx; + if (clientResponse) + { + // If we can get device's UUID from OCClientResponse, it'd be good to use it in here + // but OCIdentity in OCClientResponse is emtpy now. + // It seems that we can set identity to CAData_t *cadata in CAPrepareSendData() API + // but CA doesn't have deviceID yet. + // + //TODO: Get OCIdentity from OCClientResponse and use it for 'registerResultForRemoveDevice' + // If we can't complete this task, Provisioning Database has always stale link status + // when Remove device is called. + + if (OC_STACK_RESOURCE_DELETED == clientResponse->result) + { + res = PDMUnlinkDevices(&removeData->revokeTargetDev->doxm->deviceID, + NULL /*TODO: Replace NULL to uuid from OCClientResponse*/); + if (OC_STACK_OK != res) + { + OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one."); + registerResultForRemoveDevice(removeData, + NULL /*TODO: Replace NULL to uuid from OCClientResponse*/, + OC_STACK_INCONSISTENT_DB, true); + return OC_STACK_DELETE_TRANSACTION; + } + registerResultForRemoveDevice(removeData, + NULL /*TODO: Replace NULL to uuid from OCClientResponse*/, + OC_STACK_RESOURCE_DELETED, false); + } + else + { + registerResultForRemoveDevice(removeData, + NULL /*TODO: Replace NULL to uuid from OCClientResponse*/, + clientResponse->result, true); + OC_LOG(ERROR, TAG, "Unexpected result from DELETE credential request!"); + } + } + else + { + registerResultForRemoveDevice(removeData, NULL, OC_STACK_ERROR, true); + OC_LOG(ERROR, TAG, "SRPRemoveDevices received Null clientResponse"); + } + + return OC_STACK_DELETE_TRANSACTION; +} + +static OCStackResult GetListofDevToReqDeleteCred(const OCProvisionDev_t* pRevokeTargetDev, + OCProvisionDev_t* pOwnedDevList, + OCUuidList_t* pLinkedUuidList, + OCProvisionDev_t** ppLinkedDevList, + size_t *numOfLinkedDev) +{ + // pOwnedDevList could be NULL. It means no alived and owned device now. + if (pRevokeTargetDev == NULL || pLinkedUuidList == NULL ||\ + ppLinkedDevList == NULL || numOfLinkedDev == NULL) + { + return OC_STACK_INVALID_PARAM; + } + + size_t cnt = 0; + OCUuidList_t *curUuid = NULL, *tmpUuid = NULL; + LL_FOREACH_SAFE(pLinkedUuidList, curUuid, tmpUuid) + { + // Mark the link status stale. + OCStackResult res = PDMSetLinkStale(&curUuid->dev, &pRevokeTargetDev->doxm->deviceID); + if (OC_STACK_OK != res) + { + OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one."); + return OC_STACK_INCONSISTENT_DB; + } + + if (pOwnedDevList) + { + // If this linked device is alive (power-on), add the deivce to the list. + OCProvisionDev_t *curDev = NULL, *tmpDev = NULL; + LL_FOREACH_SAFE(pOwnedDevList, curDev, tmpDev) + { + if (memcmp(curDev->doxm->deviceID.id, curUuid->dev.id, sizeof(curUuid->dev.id)) == 0) + { + OCProvisionDev_t* targetDev = PMCloneOCProvisionDev(curDev); + if (NULL == targetDev) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevice : Cloning OCProvisionDev_t Failed."); + return OC_STACK_NO_MEMORY; + } + + LL_PREPEND(*ppLinkedDevList, targetDev); + cnt++; + break; + } + } + } + } + *numOfLinkedDev = cnt; + return OC_STACK_OK; +} + +/* +* Function to device revocation +* This function will remove credential of target device from all devices in subnet. +* +* @param[in] ctx Application context would be returned in result callback +* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds) +* @param[in] pTargetDev Device information to be revoked. +* @param[in] resultCallback callback provided by API user, callback will be called when +* credential revocation is finished. +* @return OC_STACK_OK in case of success and other value otherwise. +* If OC_STACK_OK is returned, the caller of this API should wait for callback. +* OC_STACK_CONTINUE means operation is success but no request is need to be initiated. +*/ +OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery, + const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback) +{ + OC_LOG(INFO, TAG, "IN SRPRemoveDevice"); + + if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery) + { + OC_LOG(INFO, TAG, "SRPRemoveDevice : NULL parameters"); + return OC_STACK_INVALID_PARAM; + } + + // Declare variables in here to handle error cases with goto statement. + OCProvisionDev_t* pOwnedDevList = NULL; + OCProvisionDev_t* pLinkedDevList = NULL; + RemoveData_t* removeData = NULL; + + //1. Find all devices that has a credential of the revoked device + OCUuidList_t* pLinkedUuidList = NULL; + size_t numOfDevices = 0; + OCStackResult res = OC_STACK_ERROR; + res = PDMGetLinkedDevices(&pTargetDev->doxm->deviceID, &pLinkedUuidList, &numOfDevices); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to get linked devices information"); + return res; + } + // if there is no related device, we can skip further process. + if (0 == numOfDevices) + { + OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No linked device found."); + res = OC_STACK_CONTINUE; + goto error; + } + + //2. Find owned device from the network + res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to PMDeviceDiscovery"); + goto error; + } + + //3. Make a list of devices to send DELETE credential request + // by comparing owned devices from provisioning database with mutlicast discovery result. + size_t numOfLinkedDev = 0; + res = GetListofDevToReqDeleteCred(pTargetDev, pOwnedDevList, pLinkedUuidList, + &pLinkedDevList, &numOfLinkedDev); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevice : GetListofDevToReqDeleteCred() failed"); + goto error; + } + if (0 == numOfLinkedDev) // This case means, there is linked device but it's not alive now. + { // So we don't have to send request message. + OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No alived & linked device found."); + res = OC_STACK_CONTINUE; + goto error; + } + + // 4. Prepare RemoveData Context data. + removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t)); + if (!removeData) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation"); + res = OC_STACK_NO_MEMORY; + goto error; + } + + removeData->revokeTargetDev = PMCloneOCProvisionDev(pTargetDev); + if (!removeData->revokeTargetDev) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevices : PMCloneOCProvisionDev Failed"); + res = OC_STACK_NO_MEMORY; + goto error; + } + + removeData->removeRes = + (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t)); + if (!removeData->removeRes) + { + OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation"); + res = OC_STACK_NO_MEMORY; + goto error; + } + + removeData->ctx = ctx; + removeData->linkedDevList = pLinkedDevList; + removeData->resultCallback = resultCallback; + removeData->numOfResults = 0; + removeData->sizeOfResArray = numOfLinkedDev; + removeData->hasError = false; + + // 5. Send DELETE credential request to linked devices. + OCProvisionDev_t *curDev = NULL, *tmpDev = NULL; + OCStackResult totalRes = OC_STACK_ERROR; /* variable for checking request is sent or not */ + LL_FOREACH_SAFE(pLinkedDevList, curDev, tmpDev) + { + res = SendDeleteCredentialRequest((void*)removeData, &SRPRemoveDeviceCB, + removeData->revokeTargetDev, curDev); + if (OC_STACK_OK != res) + { + OC_LOG_V(ERROR, TAG, "SRPRemoveDevice : Fail to send the DELETE credential request to\ + %s:%u", curDev->endpoint.addr, curDev->endpoint.port); + } + else + { + totalRes = OC_STACK_OK; // This means at least one request is successfully sent. + } + } + + PDMDestoryOicUuidLinkList(pLinkedUuidList); //TODO: Modify API name to have unified convention. + PMDeleteDeviceList(pOwnedDevList); + OC_LOG(INFO, TAG, "OUT SRPRemoveDevice"); + + return totalRes; // Caller of this API should wait callback if totalRes == OC_STACK_OK. + +error: + PDMDestoryOicUuidLinkList(pLinkedUuidList); + PMDeleteDeviceList(pOwnedDevList); + PMDeleteDeviceList(pLinkedDevList); + if (removeData) + { + OICFree(removeData->revokeTargetDev); + OICFree(removeData->removeRes); + OICFree(removeData); + } + OC_LOG(INFO, TAG, "OUT ERROR case SRPRemoveDevice"); + return res; +} diff --git a/resource/csdk/security/provisioning/unittest/SConscript b/resource/csdk/security/provisioning/unittest/SConscript index a6b867a..98118f9 100644 --- a/resource/csdk/security/provisioning/unittest/SConscript +++ b/resource/csdk/security/provisioning/unittest/SConscript @@ -67,7 +67,8 @@ if not env.get('RELEASE'): ###################################################################### unittest = sptest_env.Program('unittest', ['pmutilitytest.cpp', 'otmunittest.cpp', 'secureresourceprovider.cpp', - 'provisioningdatabasemanager.cpp']) + 'provisioningdatabasemanager.cpp', + 'ocprovisioningmanager.cpp' ]) Alias("test", [unittest]) diff --git a/resource/csdk/security/provisioning/unittest/ocprovisioningmanager.cpp b/resource/csdk/security/provisioning/unittest/ocprovisioningmanager.cpp new file mode 100644 index 0000000..31477c3 --- /dev/null +++ b/resource/csdk/security/provisioning/unittest/ocprovisioningmanager.cpp @@ -0,0 +1,69 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * *****************************************************************/ +#include "gtest/gtest.h" +#include "ocprovisioningmanager.h" + +static void provisioningCB (void* UNUSED1, int UNUSED2, OCProvisionResult_t *UNUSED3, bool UNUSED4) +{ + //dummy callback + (void) UNUSED1; + (void) UNUSED2; + (void) UNUSED3; + (void) UNUSED4; +} + +TEST(OCUnlinkDevicesTest, NullDevice1) +{ + OCProvisionDev_t dev2; + EXPECT_EQ(OC_STACK_INVALID_PARAM, OCUnlinkDevices(NULL, NULL, &dev2, provisioningCB)); +} + +TEST(OCUnlinkDevicesTest, NullDevice2) +{ + OCProvisionDev_t dev1; + EXPECT_EQ(OC_STACK_INVALID_PARAM, OCUnlinkDevices(NULL, &dev1, NULL, provisioningCB)); +} + +TEST(OCUnlinkDevicesTest, NullCallback) +{ + OCProvisionDev_t dev1; + OCProvisionDev_t dev2; + EXPECT_EQ(OC_STACK_INVALID_PARAM, OCUnlinkDevices(NULL, &dev1, &dev2, NULL)); +} + +TEST(OCRemoveDeviceTest, NullTargetDevice) +{ + unsigned short waitTime = 10 ; + EXPECT_EQ(OC_STACK_INVALID_PARAM, OCRemoveDevice(NULL, waitTime, NULL, provisioningCB)); +} + +TEST(OCRemoveDeviceTest, NullResultCallback) +{ + unsigned short waitTime = 10; + OCProvisionDev_t dev1; + EXPECT_EQ(OC_STACK_INVALID_PARAM, OCRemoveDevice(NULL, waitTime, &dev1, NULL)); +} + +TEST(OCRemoveDeviceTest, ZeroWaitTime) +{ + unsigned short waitTime = 0; + OCProvisionDev_t dev1; + EXPECT_EQ(OC_STACK_INVALID_PARAM, OCRemoveDevice(NULL, waitTime, &dev1, NULL)); +} \ No newline at end of file diff --git a/resource/csdk/security/provisioning/unittest/provisioningdatabasemanager.cpp b/resource/csdk/security/provisioning/unittest/provisioningdatabasemanager.cpp index 2265f60..d8cf55a 100644 --- a/resource/csdk/security/provisioning/unittest/provisioningdatabasemanager.cpp +++ b/resource/csdk/security/provisioning/unittest/provisioningdatabasemanager.cpp @@ -143,7 +143,7 @@ TEST (PDMDeleteDevice, NULLDeviceID) EXPECT_EQ(OC_STACK_INVALID_PARAM, PDMDeleteDevice(NULL)); } -TEST (PDMDeleteDevice, ValidDeviceID) +TEST (PDMDeleteDevice, ValidButNonExistDeviceID) { OicUuid_t uid = {{0,}}; @@ -156,7 +156,7 @@ TEST (PDMDeleteDevice, ValidDeviceID) } memcpy(&uid.id, &id, sizeof(uid.id)); - EXPECT_EQ(OC_STACK_OK, PDMDeleteDevice(&uid)); + EXPECT_EQ(OC_STACK_INVALID_PARAM, PDMDeleteDevice(&uid)); } TEST(PDMGetOwnedDevices, ValidCase) @@ -182,6 +182,15 @@ TEST(PDMGetLinkedDevices, ValidCase) EXPECT_EQ(OC_STACK_OK, PDMGetLinkedDevices(&uid, &list, &noOfDevices)); } +TEST(PDMGetLinkedDevices, InvalidCase) +{ + OicUuid_t uid = {{0,}}; + memcpy(&uid.id, ID_6, sizeof(uid.id)); + OCUuidList_t *list = NULL; + size_t noOfDevices = 0; + EXPECT_EQ(OC_STACK_INVALID_PARAM, PDMGetLinkedDevices(&uid, &list, &noOfDevices)); +} + TEST(PDMSetLinkStale, NULLDeviceID1) { OicUuid_t uid = {{0,}}; @@ -202,6 +211,13 @@ TEST(PDMSetLinkStale, ValidCase) memcpy(&uid1.id, ID_6, sizeof(uid1.id)); OicUuid_t uid2 = {{0,}}; memcpy(&uid2.id, ID_1, sizeof(uid2.id)); + + EXPECT_EQ(OC_STACK_INVALID_PARAM, PDMSetLinkStale(&uid1, &uid2)); + + EXPECT_EQ(OC_STACK_OK, PDMAddDevice(&uid1)); + + EXPECT_EQ(OC_STACK_OK, PDMLinkDevices(&uid1, &uid2)); + EXPECT_EQ(OC_STACK_OK, PDMSetLinkStale(&uid1, &uid2)); } diff --git a/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp b/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp index 6c8e3d6..25d2226 100644 --- a/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp +++ b/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp @@ -69,4 +69,42 @@ TEST(SRPProvisionCredentialsTest, InvalidKeySize) EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType, 0, &pDev1, &pDev2, &provisioningCB)); -} \ No newline at end of file +} + +TEST(SRPUnlinkDevicesTest, NullDevice1) +{ + OCProvisionDev_t dev2; + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPUnlinkDevices(NULL, NULL, &dev2, provisioningCB)); +} + +TEST(SRPUnlinkDevicesTest, NullDevice2) +{ + OCProvisionDev_t dev1; + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPUnlinkDevices(NULL, &dev1, NULL, provisioningCB)); +} + +TEST(SRPUnlinkDevicesTest, NullCallback) +{ + OCProvisionDev_t dev1; + OCProvisionDev_t dev2; + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPUnlinkDevices(NULL, &dev1, &dev2, NULL)); +} + +TEST(SRPRemoveDeviceTest, NullTargetDevice) +{ + unsigned short waitTime = 10 ; + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPRemoveDevice(NULL, waitTime, NULL, provisioningCB)); +} + +TEST(SRPRemoveDeviceTest, NullResultCallback) +{ + unsigned short waitTime = 10; + OCProvisionDev_t dev1; + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPRemoveDevice(NULL, waitTime, &dev1, NULL)); +} + +TEST(SRPRemoveDeviceTest, ZeroWaitTime) +{ + OCProvisionDev_t dev1; + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPRemoveDevice(NULL, 0, &dev1, NULL)); +}