/* * ESPRESSIF MIT License * * Copyright (c) 2020 * * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, * it is free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Maximum attempts allowed for Pair Setup, as per HAP Specifications */ #define HAP_PAIR_SETUP_MAX_ATTEMPTS 100 #define PAIR_SETUP_ENCRYPT_SALT "Pair-Setup-Encrypt-Salt" #define PAIR_SETUP_ENCRYPT_INFO "Pair-Setup-Encrypt-Info" #define PAIR_SETUP_CTRL_SIGN_SALT "Pair-Setup-Controller-Sign-Salt" #define PAIR_SETUP_CTRL_SIGN_INFO "Pair-Setup-Controller-Sign-Info" #define PAIR_SETUP_ACC_SIGN_SALT "Pair-Setup-Accessory-Sign-Salt" #define PAIR_SETUP_ACC_SIGN_INFO "Pair-Setup-Accessory-Sign-Info" #define PS_CTX_INIT 1 #define PS_CTX_DEINIT 2 /* Timeout if pair setup not completed in 1 minute (60sec)*/ #define HAP_SETUP_TIMEOUT_IN_TICKS ((40 * 1000) / hap_platform_os_get_msec_per_tick()) static int hap_pair_setup_process_srp_start(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) { /* Pair setup is not allowed if the accessory is already paired */ if (is_accessory_paired()) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Accessory is already paired. " "Please use \"Add Pairing\" to add more controllers"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unavailable, buf, bufsize, outlen); return HAP_FAIL; } /* Pair Setup is not allowed if the failed attempts have exceeded the * maximum allowed attempts. */ if (hap_priv.pair_attempts >= HAP_PAIR_SETUP_MAX_ATTEMPTS) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Too many attempts. Aborting"); hap_prepare_error_tlv(STATE_M2, kTLVError_MaxTries, buf, bufsize, outlen); return HAP_FAIL; } ps_ctx->ctrl = hap_controller_get_empty_loc(); if (!ps_ctx->ctrl) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No empty controller slot. Aborting"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } uint8_t state; if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || (get_value_from_tlv(buf, inlen, kTLVType_Method, &ps_ctx->method, sizeof(ps_ctx->method)) < 0)) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } if (state != STATE_M1) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M1 Received"); int flags_len; if ((flags_len = get_value_from_tlv(buf, inlen, kTLVType_Flags, &ps_ctx->pairing_flags, sizeof(ps_ctx->pairing_flags))) > 0) { ps_ctx->pairing_flags_len = flags_len; ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Got pairing flags %x", ps_ctx->pairing_flags); /* If the Split pairing flag is not set, it is an error */ if (!(ps_ctx->pairing_flags & PAIR_FLAG_SPLIT)) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Pairing Flags received, but the Split flag is not set"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } /* If either the current or the previous request didn't have transient flag set, return authentication error */ if (!((ps_ctx->pairing_flags | hap_priv.pairing_flags) & PAIR_FLAG_TRANSIENT)) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Split pairing received before preceding Transient Pairing"); hap_prepare_error_tlv(STATE_M2, kTLVError_Authentication, buf, bufsize, outlen); return HAP_FAIL; } } hap_priv.pairing_flags = ps_ctx->pairing_flags; int len_B = 0; char *bytes_B; /* Create SRP Salt and Verifier for the provided pairing PIN */ mu_srp_init(&ps_ctx->srp_hd, MU_NG_3072); /* If a setup code is explicitly set, use it */ if (hap_priv.setup_code) { ps_ctx->len_s = 16; mu_srp_srv_pubkey(&ps_ctx->srp_hd, "Pair-Setup", (const char*)hap_priv.setup_code, strlen(hap_priv.setup_code), ps_ctx->len_s, &bytes_B, &len_B, &ps_ctx->bytes_s); } else { /* Else, use the salt and verifier for SRP. This should be the default production case */ if (mu_srp_set_salt_verifier(&ps_ctx->srp_hd, (char *)hap_priv.setup_info->salt, sizeof(hap_priv.setup_info->salt), (char *)hap_priv.setup_info->verifier, sizeof(hap_priv.setup_info->verifier)) < 0) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP-6a Salt-Verifier Init Failed"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } ps_ctx->bytes_s = (char *)hap_priv.setup_info->salt; ps_ctx->len_s = sizeof(hap_priv.setup_info->salt); mu_srp_srv_pubkey_from_salt_verifier(&ps_ctx->srp_hd, &bytes_B, &len_B); } if (!ps_ctx->bytes_s || !bytes_B) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP-6a Verifier Creation Failed"); hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } hex_dbg_with_name("salt", (uint8_t *)ps_ctx->bytes_s, ps_ctx->len_s); hex_dbg_with_name("acc_srp_public_key", (uint8_t *)bytes_B, len_B); /* Construct the response M2 */ hap_tlv_data_t tlv_data; tlv_data.bufptr = buf; tlv_data.bufsize = bufsize; tlv_data.curlen = 0; state = STATE_M2; if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || (add_tlv(&tlv_data, kTLVType_PublicKey, len_B, (void *)bytes_B) < 0) || (add_tlv(&tlv_data, kTLVType_Salt, ps_ctx->len_s, ps_ctx->bytes_s) < 0 )) { hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } /* Not adding any error check here, because without the pairing flags, the pairing will * anyways fail later. */ if (ps_ctx->pairing_flags_len) { add_tlv(&tlv_data, kTLVType_Flags, ps_ctx->pairing_flags_len, &ps_ctx->pairing_flags); } *outlen = tlv_data.curlen; ps_ctx->state = state; ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M2 Successful"); hap_report_event(HAP_EVENT_PAIRING_STARTED, NULL, 0); return HAP_SUCCESS; } static int hap_pair_setup_process_srp_verify(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) { uint8_t state; char ctrl_public_key[384]; int ctrl_public_key_len; char ctrl_proof[64]; int ctrl_proof_len; if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || ((ctrl_public_key_len = get_value_from_tlv(buf, inlen, kTLVType_PublicKey, ctrl_public_key, sizeof(ctrl_public_key))) < 0) || ((ctrl_proof_len = get_value_from_tlv(buf, inlen, kTLVType_Proof, ctrl_proof, sizeof(ctrl_proof))) < 0)) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } if (state != STATE_M3) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M3 Received"); hex_dbg_with_name("ctrl_srp_public_key", (uint8_t *)ctrl_public_key, ctrl_public_key_len); hex_dbg_with_name("ctrl_proof", (uint8_t *)ctrl_proof, ctrl_proof_len); mu_srp_get_session_key(&ps_ctx->srp_hd, ctrl_public_key, ctrl_public_key_len, &ps_ctx->shared_secret, &ps_ctx->secret_len); char host_proof[SHA512HashSize]; int ret = mu_srp_exchange_proofs(&ps_ctx->srp_hd, "Pair-Setup", ctrl_proof, host_proof); if (ret != 1) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP Verify: Controller Authentication failed"); hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen); hap_report_event(HAP_EVENT_PAIRING_ABORTED, NULL, 0); return HAP_FAIL; } int acc_proof_length = SHA512HashSize; hkdf(SHA512, (uint8_t *) PAIR_SETUP_ENCRYPT_SALT, strlen(PAIR_SETUP_ENCRYPT_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len, (uint8_t *) PAIR_SETUP_ENCRYPT_INFO, strlen(PAIR_SETUP_ENCRYPT_INFO), ps_ctx->session_key, sizeof(ps_ctx->session_key)); /* Construct the response M4 */ hap_tlv_data_t tlv_data; tlv_data.bufptr = buf; tlv_data.bufsize = bufsize; tlv_data.curlen = 0; state = STATE_M4; if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || (add_tlv(&tlv_data, kTLVType_Proof, acc_proof_length, (void *)host_proof) < 0)) { hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); return HAP_FAIL; } hap_tlv_error_t tlv_error = 0; if (hap_pair_setup_manage_mfi_auth(ps_ctx, &tlv_data, &tlv_error) != ESP_OK) { hap_prepare_error_tlv(STATE_M4, tlv_error, buf, bufsize, outlen); return HAP_FAIL; } *outlen = tlv_data.curlen; ps_ctx->state = state; ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M4 Successful"); return HAP_SUCCESS; } static int hap_pair_setup_process_exchange(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) { uint8_t state; uint8_t edata[220]; int edata_len; int ret; if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || ((edata_len = get_value_from_tlv(buf, inlen, kTLVType_EncryptedData, edata, sizeof(edata))) < 0)) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); hap_prepare_error_tlv(STATE_M6, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } hex_dbg_with_name("recv_encrypted_data", edata, edata_len); if (state != STATE_M5) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); hap_prepare_error_tlv(STATE_M6, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M5 Received"); edata_len -= 16; /* 16 bytes for the authTag */ uint8_t newnonce[12]; memset(newnonce, 0, sizeof newnonce); memcpy(newnonce+4, (uint8_t *)PS_NONCE2, 8); ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(edata, NULL, edata, edata_len, &edata[edata_len], NULL, 0, newnonce, ps_ctx->session_key); if (ret != 0) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Decryption Failed"); hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen); return HAP_FAIL; } hex_dbg_with_name("subtlv", edata, edata_len); int ctrl_id_len; unsigned char ed_sign[64]; unsigned long long ed_sign_len; if (((ctrl_id_len = get_value_from_tlv(edata, edata_len, kTLVType_Identifier, ps_ctx->ctrl->info.id, sizeof(ps_ctx->ctrl->info.id))) < 0) || (get_value_from_tlv(edata, edata_len, kTLVType_PublicKey, ps_ctx->ctrl->info.ltpk, ED_KEY_LEN) != ED_KEY_LEN) || (get_value_from_tlv(edata, edata_len, kTLVType_Signature, ed_sign, sizeof(ed_sign)) != sizeof(ed_sign))) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid subTLV received"); hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen); return HAP_FAIL; } ps_ctx->ctrl->info.id[ctrl_id_len] = 0; /* NULL termination */ hex_dbg_with_name("ctrl_id", (uint8_t *)ps_ctx->ctrl->info.id, ctrl_id_len); hex_dbg_with_name("ltpkc", ps_ctx->ctrl->info.ltpk, ED_KEY_LEN); hex_dbg_with_name("ctrl_sign", ed_sign, sizeof(ed_sign)); /* Derive iOSDeviceX from SRP shared secret using HKDF-SHA512 */ uint8_t ios_device_x[32]; hkdf(SHA512, (unsigned char *) PAIR_SETUP_CTRL_SIGN_SALT, strlen(PAIR_SETUP_CTRL_SIGN_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len, (unsigned char *) PAIR_SETUP_CTRL_SIGN_INFO, strlen(PAIR_SETUP_CTRL_SIGN_INFO), ios_device_x, sizeof(ios_device_x)); /* Construct iOSDeviceInfo by concatenating * iOSDeviceX * iOSDevicePairingID (ctrl_id) * iOSDeviceLTPK (ltpkc) */ uint8_t info_buf[HAP_CTRL_ID_LEN + 32 + ED_KEY_LEN]; uint8_t *ios_dev_info = info_buf; int ios_dev_info_len = 0; memcpy(ios_dev_info, ios_device_x, sizeof(ios_device_x)); ios_dev_info_len += sizeof(ios_device_x); memcpy(&ios_dev_info[ios_dev_info_len], ps_ctx->ctrl->info.id, ctrl_id_len); ios_dev_info_len += ctrl_id_len; memcpy(&ios_dev_info[ios_dev_info_len], ps_ctx->ctrl->info.ltpk, ED_KEY_LEN); ios_dev_info_len += ED_KEY_LEN; ret = crypto_sign_ed25519_verify_detached(ed_sign, ios_dev_info, ios_dev_info_len, ps_ctx->ctrl->info.ltpk); /* Verify Signature of constructed iOSDeviceInfo using the iOSDeviceLTPK */ if (ret != 0) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid Signature"); hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen); return HAP_FAIL; } hex_dbg_with_name("ltpka", hap_priv.ltpka, sizeof(hap_priv.ltpka)); /* Derive AccessoryX from the SRP shared secret using HKDF-SHA512 */ uint8_t acc_x[32]; hkdf(SHA512, (unsigned char *) PAIR_SETUP_ACC_SIGN_SALT, strlen(PAIR_SETUP_ACC_SIGN_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len, (unsigned char *) PAIR_SETUP_ACC_SIGN_INFO, strlen(PAIR_SETUP_ACC_SIGN_INFO), acc_x, sizeof(acc_x)); /* Construct AccessoryInfo by concatenating * AccessoryX * AccessoryPairingID (acc_id) * AccessoryLTPK (ltpka) */ uint8_t *acc_info = info_buf; int acc_info_len = 0; memcpy(acc_info, acc_x, sizeof(acc_x)); acc_info_len += sizeof(acc_x); memcpy(&ios_dev_info[acc_info_len], hap_priv.acc_id, strlen(hap_priv.acc_id)); acc_info_len += strlen(hap_priv.acc_id); memcpy(&ios_dev_info[acc_info_len], hap_priv.ltpka, sizeof(hap_priv.ltpka)); acc_info_len += sizeof(hap_priv.ltpka); /* Generate AccessorySignature by signing AccessoryInfo with AccessoryLTSK */ crypto_sign_ed25519_detached(ed_sign, &ed_sign_len, acc_info, acc_info_len, hap_priv.ltska); hex_dbg_with_name("acc_sign", ed_sign, sizeof(ed_sign)); /* Create subTLV with: * kTLVType_Identifier : Accessory ID (acc_id) * kTLVType_PublicKey : Accessory LTPK * kTLVType_Signature : AccessorySignature */ uint8_t subtlv[6 + HAP_ACC_ID_LEN + ED_KEY_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN]; hap_tlv_data_t tlv_data; tlv_data.bufptr = subtlv; tlv_data.bufsize = sizeof(subtlv); tlv_data.curlen = 0; add_tlv(&tlv_data, kTLVType_Identifier, strlen(hap_priv.acc_id), hap_priv.acc_id); add_tlv(&tlv_data, kTLVType_PublicKey, sizeof(hap_priv.ltpka), hap_priv.ltpka); add_tlv(&tlv_data, kTLVType_Signature, sizeof(ed_sign), ed_sign); int subtlv_len = tlv_data.curlen; hex_dbg_with_name("subtlv", subtlv, subtlv_len); /* Encrypt the subTLV using the session key */ unsigned long long mlen = 16; memset(newnonce, 0, sizeof newnonce); memcpy(newnonce+4, (uint8_t *) PS_NONCE3, 8); crypto_aead_chacha20poly1305_ietf_encrypt_detached(subtlv, &subtlv[subtlv_len], &mlen, subtlv, subtlv_len, NULL, 0, NULL, newnonce, ps_ctx->session_key); hex_dbg_with_name("send_encrypt_data", subtlv, subtlv_len + 16); /* Construct the response M6 */ tlv_data.bufptr = buf; tlv_data.bufsize = bufsize; tlv_data.curlen = 0; state = STATE_M6; if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || (add_tlv(&tlv_data, kTLVType_EncryptedData, subtlv_len + 16, subtlv) < 0)) { hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } *outlen = tlv_data.curlen; ps_ctx->state = state; ps_ctx->ctrl->info.perms = 1; /* Controller added using pair setup is always an admin */ ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup Successful for %s", ps_ctx->ctrl->info.id); /* Reset the Pairing Attempts count */ hap_priv.pair_attempts = 0; hap_controller_save(ps_ctx->ctrl); hap_send_event(HAP_INTERNAL_EVENT_ACC_PAIRED); return HAP_SUCCESS; } static uint8_t hap_pair_setup_get_received_state(uint8_t *buf, int inlen) { uint8_t state = 0; get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)); return state; } static void hap_pair_setup_timeout(TimerHandle_t handle) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Clearing Pair Setup Context due to inactivity"); pair_setup_ctx_t *ps_ctx = pvTimerGetTimerID(handle); if (ps_ctx) { httpd_sess_trigger_close(hap_priv.server, ps_ctx->sock_fd); hap_report_event(HAP_EVENT_PAIRING_ABORTED, NULL, 0); } } /* Pair Setup can have only a single context at a time as the specification does not allow * multiple controllers to perform Pair Setup Simultaneously. * * The purpose of this function is to manage allocation and resetting of the context by * using a static variable rather than a global variable. */ static pair_setup_ctx_t *hap_pair_setup_ctx_action(int action) { static pair_setup_ctx_t *ps_ctx; /* If the call is to initialise the context, check if it is already * initialised. */ if (action == PS_CTX_INIT) { /* If the context is already initialised, it means that pair setup * is already in progress. So, return NULL. * Else, allocate the context. */ if (ps_ctx) return NULL; else { ps_ctx = hap_platform_memory_calloc(sizeof(pair_setup_ctx_t), 1); if (ps_ctx) { ps_ctx->timer = xTimerCreate("hap_setup_timer", HAP_SETUP_TIMEOUT_IN_TICKS, pdFALSE, (void *) ps_ctx, hap_pair_setup_timeout); xTimerStart(ps_ctx->timer, 0); } } } else if (action == PS_CTX_DEINIT) { /* If the call is to de-initialise the context, clean it up * and set the pointer to NULL */ if (ps_ctx) { if (ps_ctx->timer) { xTimerStop(ps_ctx->timer, 0); xTimerDelete(ps_ctx->timer, 100); } mu_srp_free(&ps_ctx->srp_hd); hap_platform_memory_free(ps_ctx); } ps_ctx = NULL; } return ps_ctx; } void hap_pair_setup_ctx_clean(void *sess_ctx) { if (sess_ctx) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Cleaning Pair Setup Context"); hap_pair_setup_ctx_action(PS_CTX_DEINIT); } } int hap_pair_setup_context_init(int sock_fd, void **ctx, uint8_t *buf, int bufsize, int *outlen) { pair_setup_ctx_t *ps_ctx = hap_pair_setup_ctx_action(PS_CTX_INIT); if (!ps_ctx) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR,"######## Aborted! Pair Setup in Progress with another controller ########"); hap_prepare_error_tlv(STATE_M2, kTLVError_Busy, buf, bufsize, outlen); return HAP_FAIL; } ps_ctx->sock_fd = sock_fd; *ctx = ps_ctx; ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "######## Starting Pair Setup ########"); return HAP_SUCCESS; } int hap_pair_setup_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) { pair_setup_ctx_t *ps_ctx = (pair_setup_ctx_t *)(*ctx); uint8_t recv_state = hap_pair_setup_get_received_state(buf, inlen); if (!ps_ctx) { hap_prepare_error_tlv(recv_state + 1, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } /* Receiving STATE_M1 in the message while the pair-setup was already in progress means * that pair setup was restarted. Handle it accordingly */ if ((recv_state == STATE_M1) && (ps_ctx->state != STATE_M0)) { ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Restarting Pair Setup"); int sock_fd = ps_ctx->sock_fd; hap_pair_setup_ctx_clean(ps_ctx); int ret = hap_pair_setup_context_init(sock_fd, ctx, buf, bufsize, outlen); if (ret != HAP_SUCCESS) return ret; ps_ctx = (pair_setup_ctx_t *)(*ctx); } if (ps_ctx->state == STATE_M0) { return hap_pair_setup_process_srp_start(ps_ctx, buf, inlen, bufsize, outlen); } else if (ps_ctx->state == STATE_M2) { hap_priv.pair_attempts++; int ret = hap_pair_setup_process_srp_verify(ps_ctx, buf, inlen, bufsize, outlen); if (ps_ctx->session) { *ctx = ps_ctx->session; hap_pair_setup_ctx_clean(ps_ctx); } return ret; } else if (ps_ctx->state == STATE_M4) { int ret = hap_pair_setup_process_exchange(ps_ctx, buf, inlen, bufsize, outlen); /* If last step of pair setup is successful, it means that the context would * be no more required. Hence, clear it. */ if (ret == HAP_SUCCESS) { hap_pair_setup_ctx_clean(ps_ctx); *ctx = NULL; } return ret; } hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); return HAP_FAIL; } void hap_set_setup_code(const char *setup_code) { if (hap_priv.setup_code) hap_platform_memory_free(hap_priv.setup_code); hap_priv.setup_code = strdup(setup_code); } int hap_set_setup_info(const hap_setup_info_t *setup_info) { if (!setup_info) return HAP_FAIL; if (hap_priv.setup_info) hap_platform_memory_free(hap_priv.setup_info); hap_priv.setup_info = hap_platform_memory_calloc(1, sizeof(hap_setup_info_t)); if (!hap_priv.setup_info) return HAP_FAIL; memcpy(hap_priv.setup_info, setup_info, sizeof(hap_setup_info_t)); return HAP_SUCCESS; } int hap_set_setup_id(const char *setup_id) { if (setup_id == NULL || strlen(setup_id) != SETUP_ID_LEN) return HAP_FAIL; strcpy(hap_priv.setup_id, setup_id); return HAP_SUCCESS; }