static OCStackResult RemoveDeviceInfoFromLocal(const OCProvisionDev_t* pTargetDev)
{
    // Remove credential of revoked device from SVR database
    OCStackResult res = OC_STACK_ERROR;
    const OicSecCred_t *cred = NULL;
    cred = GetCredResourceData(&pTargetDev->doxm->deviceID);
    if (cred == NULL)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device.");
        goto error;
    }

    res = RemoveCredential(&cred->subject);
    if (res != OC_STACK_RESOURCE_DELETED)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential.");
        goto error;
    }

    /**
     * Change the device status as stale status.
     * If all request are successed, this device information will be deleted.
     */
    res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
    if (res != OC_STACK_OK)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to set device status as stale");
        goto error;
    }

    // TODO: We need to add new mechanism to clean up the stale state of the device.

    //Close the DTLS session of the removed device.
    CAEndpoint_t* endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
    endpoint->port = pTargetDev->securePort;
    CAResult_t caResult = CACloseDtlsSession(endpoint);
    if(CA_STATUS_OK != caResult)
    {
        OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
    }

error:
    return res;
}
/**
 * Callback handler for OwnershipInformationHandler API.
 *
 * @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 OwnershipInformationHandler(void *ctx, OCDoHandle UNUSED,
                                OCClientResponse *clientResponse)
{
    VERIFY_NON_NULL(TAG, clientResponse, WARNING);
    VERIFY_NON_NULL(TAG, ctx, WARNING);

    OC_LOG(DEBUG, TAG, "IN OwnershipInformationHandler");
    (void)UNUSED;
    OCStackResult res = OC_STACK_OK;
    OTMContext_t* otmCtx = (OTMContext_t*)ctx;
    if  (OC_STACK_OK == clientResponse->result)
    {
        if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel)
        {
            res = RemoveCredential(&otmCtx->subIdForPinOxm);
            if(OC_STACK_RESOURCE_DELETED != res)
            {
                OC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);
                return OC_STACK_DELETE_TRANSACTION;
            }
        }

        res = SaveOwnerPSK(otmCtx->selectedDeviceInfo);
        if(OC_STACK_OK != res)
        {
            OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to owner PSK generation");
            SetResult(otmCtx, res);
            return OC_STACK_DELETE_TRANSACTION;
        }

        CAEndpoint_t* endpoint = (CAEndpoint_t *)&otmCtx->selectedDeviceInfo->endpoint;
        endpoint->port = otmCtx->selectedDeviceInfo->securePort;
        CAResult_t caResult = CACloseDtlsSession(endpoint);
        if(CA_STATUS_OK != caResult)
        {
            OC_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.
         */
        caResult = CASelectCipherSuite(TLS_NULL_WITH_NULL_NULL);
        if(CA_STATUS_OK != caResult)
        {
            OC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
            SetResult(otmCtx, caResult);
            return OC_STACK_DELETE_TRANSACTION;
        }

        OC_LOG(INFO, TAG, "Ownership transfer was successfully completed.");
        OC_LOG(INFO, TAG, "Start defualt ACL & commit-hash provisioning.");

        res = FinalizeProvisioning(otmCtx);
        if(OC_STACK_OK != res)
        {
            SetResult(otmCtx, res);
        }
    }
    else
    {
        res = clientResponse->result;
    }

    OC_LOG(DEBUG, TAG, "OUT OwnershipInformationHandler");

exit:
    return  OC_STACK_DELETE_TRANSACTION;
}
/*
* 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)
{
    OIC_LOG(INFO, TAG, "IN OCRemoveDevice");
    OCStackResult res = OC_STACK_ERROR;
    if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
    {
        OIC_LOG(INFO, TAG, "OCRemoveDevice : Invalied parameters");
        return OC_STACK_INVALID_PARAM;
    }
    if (!resultCallback)
    {
        OIC_LOG(INFO, TAG, "OCRemoveDevice : NULL Callback");
        return OC_STACK_INVALID_CALLBACK;
    }

    // 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)
        {
            OIC_LOG(DEBUG, TAG, "OCRemoveDevice : Revoked device has no linked device except PT.");
        }
        else
        {
            OIC_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)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device.");
        goto error;
    }

    res = RemoveCredential(&cred->subject);
    if (res != OC_STACK_RESOURCE_DELETED)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential.");
        goto error;
    }

    /**
     * Change the device status as stale status.
     * If all request are successed, this device information will be deleted.
     */
    res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
    if (res != OC_STACK_OK)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to set device status as stale");
        goto error;
    }

    // TODO: We need to add new mechanism to clean up the stale state of the device.

    res = resReq;

    //Close the DTLS session of the removed device.
    CAEndpoint_t* endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
    endpoint->port = pTargetDev->securePort;
    CAResult_t caResult = CACloseDtlsSession(endpoint);
    if(CA_STATUS_OK != caResult)
    {
        OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
    }

    /**
     * If there is no linked device, PM does not send any request.
     * So we should directly invoke the result callback to inform the result of OCRemoveDevice.
     */
    if(OC_STACK_CONTINUE == res)
    {
        if(resultCallback)
        {
            resultCallback(ctx, 0, NULL, false);
        }
        res = OC_STACK_OK;
    }

error:
    OIC_LOG(INFO, TAG, "OUT OCRemoveDevice");
    return res;
}
/**
 * Function to handle the handshake result in OTM.
 * This function will be invoked after DTLS handshake
 * @param   endPoint  [IN] The remote endpoint.
 * @param   errorInfo [IN] Error information from the endpoint.
 * @return  NONE
 */
void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
{
    if(g_otmCtx && endpoint && info)
    {
        OC_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)
        {
            OCStackResult res;

            CARegisterDTLSHandshakeCallback(NULL);

            //In case of success, send next coaps request.
            if(CA_STATUS_OK == info->result)
            {
                //Send request : PUT /oic/sec/doxm [{"Owned":"True", .. , "Owner":"PT's UUID"}]
                res = PutOwnershipInformation(g_otmCtx);
                if(OC_STACK_OK != res)
                {
                    OC_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)
            {
                g_otmCtx->selectedDeviceInfo->doxm->owned = false;
                g_otmCtx->attemptCnt++;

                if(g_otmCtx->selectedDeviceInfo->doxm->oxmSel == OIC_RANDOM_DEVICE_PIN)
                {
                    res = RemoveCredential(&g_otmCtx->subIdForPinOxm);
                    if(OC_STACK_RESOURCE_DELETED != res)
                    {
                        OC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);
                        SetResult(g_otmCtx, res);
                        return;
                    }

                    if(WRONG_PIN_MAX_ATTEMP > g_otmCtx->attemptCnt)
                    {
                        res = StartOwnershipTransfer(g_otmCtx, g_otmCtx->selectedDeviceInfo);
                        if(OC_STACK_OK != res)
                        {
                            SetResult(g_otmCtx, res);
                            OC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
                        }
                    }
                    else
                    {
                        SetResult(g_otmCtx, OC_STACK_AUTHENTICATION_FAILURE);
                    }
                }
                else
                {
                    SetResult(g_otmCtx, OC_STACK_AUTHENTICATION_FAILURE);
                }
            }
        }
    }
}
Example #5
0
static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * ehRequest)
{
    OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing PUT request");
    OCEntityHandlerResult ehRet = OC_EH_ERROR;
    OicUuid_t emptyOwner = {.id = {0}};

    /*
     * Convert JSON Doxm data into binary. This will also validate
     * the Doxm data received.
     */
    OicSecDoxm_t* newDoxm = JSONToDoxmBin(((OCSecurityPayload*)ehRequest->payload)->securityData);

    if (newDoxm)
    {
        // Iotivity SRM ONLY supports OIC_JUST_WORKS now
        if (OIC_JUST_WORKS == newDoxm->oxmSel)
        {
            /*
             * If current state of the device is un-owned, enable
             * anonymous ECDH cipher in tinyDTLS so that Provisioning
             * tool can initiate JUST_WORKS ownership transfer process.
             */
            if ((false == gDoxm->owned) && (false == newDoxm->owned))
            {
                OIC_LOG (INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
#ifdef __WITH_DTLS__
                ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
#endif //__WITH_DTLS__
                goto exit;
            }

            /*
             * When current state of the device is un-owned and Provisioning
             * Tool is attempting to change the state to 'Owned' with a
             * qualified value for the field 'Owner'
             */
            if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
                (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0))
            {
                /*
                 * Generate OwnerPSK and create credential for Provisioning
                 * tool with the generated OwnerPSK.
                 * Update persistent storage and disable anonymous ECDH cipher
                 *
                 */
#ifdef __WITH_DTLS__
                OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;

                //Generating OwnerPSK
                OIC_LOG (INFO, TAG, "Doxm EntityHandle  generating OwnerPSK");

                //Generate new credential for provisioning tool
                ehRet = AddOwnerPSK((CAEndpoint_t *)&request->devAddr, newDoxm,
                        (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS));

                VERIFY_SUCCESS(TAG, OC_EH_OK == ehRet, ERROR);

                // Update new state in persistent storage
                if (true == UpdatePersistentStorage(gDoxm))
                {
                    ehRet = OC_EH_OK;
                }
                else
                {
                    ehRet = OC_EH_ERROR;

                    /*
                     * If persistent storage update failed, revert back the state
                     * for global variable.
                     */
                    gDoxm->owned = false;
                    gDoxm->oxmSel = 0;
                    memset(&(gDoxm->owner), 0, sizeof(OicUuid_t));
                }

                /*
                 * Disable anonymous ECDH cipher in tinyDTLS since device is now
                 * in owned state.
                 */
                CAEnableAnonECDHCipherSuite(false);
#ifdef __WITH_X509__
#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE
                CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
#endif //__WITH_X509__
#endif //__WITH_DTLS__
            }
        }
        else if(OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
        {
#ifdef __WITH_DTLS__
            //this temp Credential ID is used to track temporal Cred Id
            static OicUuid_t tmpCredId = {.id={0}};
            static bool tmpCredGenFlag = false;
#endif //__WITH_DTLS__

            if ((false == gDoxm->owned) && (false == newDoxm->owned))
            {
#ifdef __WITH_DTLS__
                CAEnableAnonECDHCipherSuite(false);
                OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
                CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);

                char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,};
                if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
                {
                    if(tmpCredGenFlag)
                    {
                       OIC_LOG(INFO, TAG, "Corrupted PSK is detected!!!");
                       VERIFY_SUCCESS(TAG,
                                      OC_STACK_RESOURCE_DELETED == RemoveCredential(&tmpCredId),
                                      ERROR);
                    }

                    OCStackResult res = AddTmpPskWithPIN( &(newDoxm->owner), SYMMETRIC_PAIR_WISE_KEY,
                                     ranPin, OXM_RANDOM_PIN_SIZE, 1, &(newDoxm->owner), &tmpCredId);
                    VERIFY_SUCCESS(TAG, res == OC_STACK_OK, ERROR);
                    tmpCredGenFlag = true;
                    ehRet = OC_EH_OK;
                }
                else
                {
                    OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
                    ehRet = OC_EH_ERROR;
                }

#endif //__WITH_DTLS__
            }

            /*
             * When current state of the device is un-owned and Provisioning
             * Tool is attempting to change the state to 'Owned' with a
             * qualified value for the field 'Owner'
             */
            if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
                (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0))
            {
#ifdef __WITH_DTLS__
                OCServerRequest * request = (OCServerRequest *)ehRequest->requestHandle;

                //Remove Temporal Credential resource
                if(tmpCredGenFlag)
                {
                    VERIFY_SUCCESS(TAG,
                                   OC_STACK_RESOURCE_DELETED == RemoveCredential(&tmpCredId),
                                   ERROR);
                    tmpCredGenFlag = false;
                }

                //Generate new credential for provisioning tool
                ehRet = AddOwnerPSK((CAEndpoint_t*)(&request->devAddr), newDoxm,
                                    (uint8_t*)OXM_RANDOM_DEVICE_PIN, strlen(OXM_RANDOM_DEVICE_PIN));
                VERIFY_SUCCESS(TAG, OC_EH_OK == ehRet, ERROR);

                //Update new state in persistent storage
                if((UpdatePersistentStorage(gDoxm) == true))
                {
                    ehRet = OC_EH_OK;
                }
                else
                {
                    /*
                     * If persistent storage update failed, revert back the state
                     * for global variable.
                     */
                    gDoxm->owned = false;
                    gDoxm->oxmSel = 0;
                    memset(&(gDoxm->owner), 0, sizeof(OicUuid_t));
                    ehRet = OC_EH_ERROR;

                }
#endif
             }
        }
    }

exit:

    //Send payload to request originator
    if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL))
    {
        OIC_LOG (ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
    }
    DeleteDoxmBinData(newDoxm);

    return ehRet;
}