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); } } } } }
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; }