Tasmota/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.c
2021-03-11 14:48:59 +01:00

564 lines
22 KiB
C

/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* 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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>
#include <mu_srp.h>
#include <sodium/crypto_aead_chacha20poly1305.h>
#include <hkdf-sha.h>
#include <sodium/crypto_sign_ed25519.h>
#include <hexdump.h>
#include <hap_platform_memory.h>
#include <hap_platform_os.h>
#include <esp_hap_pair_common.h>
#include <esp_hap_pair_setup.h>
#include <esp_hap_database.h>
#include <esp_hap_main.h>
#include <esp_hap_acc.h>
#include <esp_mfi_debug.h>
/* 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;
}