+ for (size_t i = 0; i < numberOfMethods; i++)
+ {
+ if (*selectedMethod == supportedMethods[i])
+ {
+ isValidOxmsel = true;
+ break;
+ }
+ }
+ if (!isValidOxmsel)
+ {
+ OIC_LOG(ERROR, TAG, "Not allowed Oxmsel.");
+ return isValidOxmsel;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT ValidateOxmsel");
+
+ return isValidOxmsel;
+}
+
+void SetInformOxmSelCB(InformOxmSelectedCallback_t informOxmSelCB)
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+ g_InformOxmSelectedCallback = informOxmSelCB;
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+}
+
+void UnsetInformOxmSelCB()
+{
+ OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+ g_InformOxmSelectedCallback = NULL;
+ OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+}
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest);
+
+static void DestroyEntityHandlerRequest(OCEntityHandlerRequest * ehRequest)
+{
+ if (ehRequest == NULL) {
+ OIC_LOG(WARNING, TAG, "ehRequest is NULL");
+ return;
+ }
+
+ OICFree(ehRequest->query);
+
+ if (ehRequest->payload) {
+ OICFree(((OCSecurityPayload *)ehRequest->payload)->securityData);
+ OICFree(ehRequest->payload);
+ }
+
+ OICFree(ehRequest);
+}
+
+void * WaitConfirm(OCEntityHandlerRequest * ehRequest)
+{
+ bool confirmResult = false, confirmState = false;
+
+ oc_mutex_lock(g_mutexWait);
+ oc_cond_wait(g_condWait, g_mutexWait);
+ oc_cond_free(g_condWait);
+ g_condWait = NULL;
+
+ oc_mutex_unlock(g_mutexWait);
+ oc_mutex_free(g_mutexWait);
+ g_mutexWait = NULL;
+
+ g_isConfirmResult = true;
+ GetAsyncVerifyUserResult(&confirmResult, &confirmState);
+ if (confirmResult == true)
+ {
+ gConfirmState = CONFIRM_STATE_ACCEPTED;
+ HandleDoxmPostRequest(ehRequest);
+ g_isConfirmResult = false;
+ }
+ else
+ {
+ gConfirmState = CONFIRM_STATE_DENIED;
+ HandleDoxmPostRequest(ehRequest);
+ g_isConfirmResult = false;
+ }
+
+ DestroyEntityHandlerRequest(ehRequest);
+
+ return NULL;
+}
+
+static OCEntityHandlerRequest *CopyRequest(OCEntityHandlerRequest *entityHandlerRequest)
+{
+ OIC_LOG(INFO, TAG, "Copying received request for slow response");
+
+ if (!entityHandlerRequest)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s: entityHandlerRequest is NULL", __func__);
+ return NULL;
+ }
+
+ OCEntityHandlerRequest *copyOfRequest =
+ (OCEntityHandlerRequest *)OICCalloc(1, sizeof(OCEntityHandlerRequest));
+ if(!copyOfRequest)
+ {
+ OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+ return NULL;
+ }
+
+ memcpy(copyOfRequest, entityHandlerRequest, sizeof(OCEntityHandlerRequest));
+
+ if (entityHandlerRequest->query)
+ {
+ copyOfRequest->query = OICStrdup(entityHandlerRequest->query);
+ if(!copyOfRequest->query)
+ {
+ OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+ OICFree(copyOfRequest);
+ return NULL;
+ }
+ }
+
+ if (entityHandlerRequest->payload)
+ {
+ copyOfRequest->payload =
+ (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload));
+ if(!copyOfRequest->payload)
+ {
+ OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+ OICFree(copyOfRequest->query);
+ OICFree(copyOfRequest);
+ return NULL;
+ }
+
+ if (((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize)
+ {
+ ((OCSecurityPayload *)copyOfRequest->payload)->securityData =
+ (uint8_t *)OICCalloc(1, ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+ if(!((OCSecurityPayload *)copyOfRequest->payload)->securityData)
+ {
+ OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+ OICFree(copyOfRequest->payload);
+ OICFree(copyOfRequest->query);
+ OICFree(copyOfRequest);
+ return NULL;
+ }
+
+ memcpy(((OCSecurityPayload *)copyOfRequest->payload)->securityData,
+ ((OCSecurityPayload *)entityHandlerRequest->payload)->securityData,
+ ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+
+ ((OCSecurityPayload *)(copyOfRequest->payload))->payloadSize =
+ ((OCSecurityPayload *)(entityHandlerRequest->payload))->payloadSize;
+ }
+
+ copyOfRequest->payload->type = entityHandlerRequest->payload->type;
+ copyOfRequest->messageID = entityHandlerRequest->messageID;
+ }
+
+ // Ignore vendor specific header options for example
+ copyOfRequest->numRcvdVendorSpecificHeaderOptions = 0;
+ copyOfRequest->rcvdVendorSpecificHeaderOptions = NULL;
+
+ OIC_LOG(INFO, TAG, "Copied client request");
+
+ return copyOfRequest;
+}
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest)
+{
+ OIC_LOG (DEBUG, TAG, "Doxm EntityHandle processing POST request");
+ OCEntityHandlerResult ehRet = OC_EH_ERROR;
+ OicUuid_t emptyOwner = {.id = {0} };
+ static uint16_t previousMsgId = 0;
+ bool isDuplicatedMsg = false;
+
+ /*
+ * Convert CBOR Doxm data into binary. This will also validate
+ * the Doxm data received.
+ */
+ OicSecDoxm_t *newDoxm = NULL;
+
+ if (ehRequest->payload)
+ {
+ uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
+ size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
+ bool roParsed = false;
+ OCStackResult res = CBORPayloadToDoxmBin(payload, size, &newDoxm, &roParsed);
+ if (newDoxm && OC_STACK_OK == res)
+ {
+ /*
+ * message ID is supported for CoAP over UDP only according to RFC 7252
+ * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
+ * In case of other transport adapter, duplicate message check is not required.
+ */
+ if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
+ previousMsgId == ehRequest->messageID && g_isConfirmResult == false)
+ {
+ isDuplicatedMsg = true;
+ }
+
+ if (isDuplicatedMsg && ehRequest->messageID == gConfirmMsgId)
+ {
+ if (CONFIRM_STATE_WAIT == gConfirmState)
+ {
+ OIC_LOG(DEBUG, TAG, "Confirm callback already invoked.");
+ OIC_LOG(DEBUG, TAG, "This request will be ignored.");
+ DeleteDoxmBinData(newDoxm);
+ return OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG_V(DEBUG, TAG, "Confirm request already done, Confirm Result = %s", (CONFIRM_STATE_ACCEPTED == gConfirmState ? "ACCEPTED" : "DENIED"));
+ ehRet = (CONFIRM_STATE_ACCEPTED == gConfirmState ? OC_EH_OK : OC_EH_NOT_ACCEPTABLE);
+ goto exit;
+ }
+ }
+
+ // Check request on RO property
+ if (true == roParsed)
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only propertys");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ goto exit;
+ }
+
+ VERIFY_NON_NULL(TAG, gDoxm, ERROR);
+
+ // in owned state
+ if (true == gDoxm->owned)
+ {
+ if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ goto exit;
+ }
+
+ if(0 != memcmp(&gDoxm->owner.id, &newDoxm->owner.id, sizeof(gDoxm->owner.id)))
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request for owned property");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ }
+
+ //Update gDoxm based on newDoxm
+ updateWriteableProperty(newDoxm, gDoxm);
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#ifdef MULTIPLE_OWNER
+ //handle mom
+ if(gDoxm->mom)
+ {
+ if(OIC_MULTIPLE_OWNER_DISABLE != gDoxm->mom->mode)
+ {
+ CAResult_t caRes = CA_STATUS_FAILED;
+ if(OIC_PRECONFIG_PIN == gDoxm->oxmSel || OIC_RANDOM_DEVICE_PIN == gDoxm->oxmSel)
+ {
+ caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, ehRequest->devAddr.adapter);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
+
+ //Set the device id to derive temporal PSK
+ SetUuidForPinBasedOxm(&gDoxm->deviceID);
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
+ }
+
+ CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
+ }
+ else
+ {
+ //if MOM is disabled, revert the DTLS handshake callback
+ if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL))
+ {
+ OIC_LOG(WARNING, TAG, "Error while revert the DTLS Handshake Callback.");
+ }
+ }
+ }
+
+ if(newDoxm->subOwners)
+ {
+ OicSecSubOwner_t* subowner = NULL;
+ OicSecSubOwner_t* temp = NULL;
+
+ OIC_LOG(DEBUG, TAG, "dectected 'subowners' property");
+
+ if(gDoxm->subOwners)
+ {
+ LL_FOREACH_SAFE(gDoxm->subOwners, subowner, temp)
+ {
+ LL_DELETE(gDoxm->subOwners, subowner);
+ OICFree(subowner);
+ }
+ }
+
+ subowner = NULL;
+ temp = NULL;
+ LL_FOREACH_SAFE(newDoxm->subOwners, subowner, temp)
+ {
+ LL_DELETE(newDoxm->subOwners, subowner);
+ LL_APPEND(gDoxm->subOwners, subowner);
+ }
+ }
+#endif //MULTIPLE_OWNER
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
+ //Update new state in persistent storage
+ if (UpdatePersistentStorage(gDoxm) == true)
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ }
+ goto exit;
+ }
+
+ // in unowned state
+ if ((false == gDoxm->owned) && (false == newDoxm->owned))
+ {
+ if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
+ {
+ OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ goto exit;
+ }
+ if (g_InformOxmSelectedCallback)
+ {
+ g_InformOxmSelectedCallback(newDoxm->oxmSel);
+ }
+
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+ if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ {
+ InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+ NULL, OIC_OTM_STARTED);
+ }
+ else
+ {
+ OIC_LOG_V(INFO, TAG, "%s: request owner not empty",__func__);
+ char* strUuid = NULL;
+ if (OC_STACK_OK == ConvertUuidToStr(&newDoxm->owner, &strUuid))
+ {
+ OIC_LOG_V(INFO, TAG, "%s: request owner: %s",__func__, strUuid);
+ OICFree(strUuid);
+ }
+ }
+#endif
+
+ if (OIC_JUST_WORKS == newDoxm->oxmSel || OIC_MV_JUST_WORKS == newDoxm->oxmSel)
+ {
+ /*
+ * If current state of the device is un-owned, enable
+ * anonymous ECDH cipher in tinyDTLS so that Provisioning
+ * tool can initiate JUST_WORKS ownership transfer process.
+ */
+ if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ {
+ gDoxm->oxmSel = newDoxm->oxmSel;
+ //Update new state in persistent storage
+ if ((UpdatePersistentStorage(gDoxm) == true))
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+ }
+ OIC_LOG (INFO, TAG, "Doxm EntityHandle enabling AnonECDHCipherSuite");
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ goto exit;
+ }
+ else
+ {
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ //Save the owner's UUID to derive owner credential
+ memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
+
+ // Update new state in persistent storage
+ if (true == UpdatePersistentStorage(gDoxm))
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+ }
+
+ /*
+ * Disable anonymous ECDH cipher in tinyDTLS since device is now
+ * in owned state.
+ */
+ CAResult_t caRes = CA_STATUS_OK;
+ caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ //In case of Mutual Verified Just-Works, verify mutualVerifNum
+ if (OIC_MV_JUST_WORKS == newDoxm->oxmSel && false == newDoxm->owned &&
+ false == isDuplicatedMsg)
+ {
+ uint8_t preMutualVerifNum[OWNER_PSK_LENGTH_128] = {0};
+ uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN] = {0};
+ OicUuid_t deviceID = {.id = {0}};
+
+ //Generate mutualVerifNum
+ OCServerRequest * request = GetServerRequestUsingHandle(ehRequest->requestHandle);
+
+ char label[LABEL_LEN] = {0};
+ snprintf(label, LABEL_LEN, "%s%s", MUTUAL_VERIF_NUM, OXM_MV_JUST_WORKS);
+ if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))
+ {
+ OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+
+ }
+
+ CAResult_t pskRet = CAGenerateOwnerPSK((CAEndpoint_t *)&request->devAddr,
+ (uint8_t *)label,
+ strlen(label),
+ gDoxm->owner.id, sizeof(gDoxm->owner.id),
+ gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id),
+ preMutualVerifNum, OWNER_PSK_LENGTH_128);
+ if (CA_STATUS_OK != pskRet)
+ {
+ OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential");
+ ehRet = OC_EH_ERROR;
+ goto exit;
+
+ }
+
+ memcpy(mutualVerifNum, preMutualVerifNum + OWNER_PSK_LENGTH_128 - sizeof(mutualVerifNum),
+ sizeof(mutualVerifNum));
+
+ gConfirmMsgId = ehRequest->messageID;
+ gConfirmState = CONFIRM_STATE_WAIT;
+ //Wait for user confirmation
+ if (OC_STACK_OK != VerifyOwnershipTransfer(mutualVerifNum, DISPLAY_NUM | USER_CONFIRM))
+ {
+ ehRet = OC_EH_NOT_ACCEPTABLE;
+ gConfirmState = CONFIRM_STATE_DENIED;
+ }
+ else
+ {
+ ehRet = OC_EH_OK;
+ gConfirmState = CONFIRM_STATE_ACCEPTED;
+ }
+ }
+
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ }
+ }
+ else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
+ {
+ /*
+ * If current state of the device is un-owned, enable
+ * anonymous ECDH cipher in tinyDTLS so that Provisioning
+ * tool can initiate JUST_WORKS ownership transfer process.
+ */
+ if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
+ {
+ gDoxm->oxmSel = newDoxm->oxmSel;
+ //Update new state in persistent storage
+ if ((UpdatePersistentStorage(gDoxm) == true))
+ {
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
+ ehRet = OC_EH_ERROR;
+ }
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ CAResult_t caRes = CA_STATUS_OK;
+
+ caRes = CAEnableAnonECDHCipherSuite(false);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+ caRes = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ ehRequest->devAddr.adapter);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+
+ if (!isDuplicatedMsg)
+ {
+ char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
+ if (OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
+ {
+ //Set the device id to derive temporal PSK
+ SetUuidForPinBasedOxm(&gDoxm->deviceID);
+
+ /**
+ * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
+ * Credential should not be saved into SVR.
+ * For this reason, use a temporary get_psk_info callback to random PIN OxM.
+ */
+ caRes = CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm);
+ VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+ ehRet = OC_EH_OK;
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
+ ehRet = OC_EH_ERROR;
+ }
+ }
+#endif // __WITH_DTLS__ or __WITH_TLS__
+ }
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)