diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:08:59 +0200 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:12:21 +0200 |
commit | 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a (patch) | |
tree | ab49cc16ed0b853452c5c2ed2d3042416d628986 /thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central/experimental/ble_nfc_pairing_reference_c/nfc_pair_m.c | |
download | iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.tar.gz iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.tar.bz2 iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.tar.xz iot-sensors-3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a.zip |
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central/experimental/ble_nfc_pairing_reference_c/nfc_pair_m.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central/experimental/ble_nfc_pairing_reference_c/nfc_pair_m.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central/experimental/ble_nfc_pairing_reference_c/nfc_pair_m.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central/experimental/ble_nfc_pairing_reference_c/nfc_pair_m.c new file mode 100644 index 0000000..d1abd59 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central/experimental/ble_nfc_pairing_reference_c/nfc_pair_m.c @@ -0,0 +1,530 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdint.h> +#include "nfc_pair_m.h" +#include "nrf_delay.h" +#include "app_error.h" +#include "bsp.h" +#include "sdk_macros.h" +#include "adafruit_pn532.h" +#include "nfc_t2t_parser.h" +#include "nfc_ndef_msg_parser.h" +#include "nfc_le_oob_rec_parser.h" +#include "ble_m.h" +#include "ecc.h" +#include "peer_manager.h" +#include "nrf_drv_rng.h" +#include "nrf_sdh_ble.h" + +#define NRF_LOG_MODULE_NAME NFC_PAIR_M +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define NFC_BLE_PAIR_OBSERVER_PRIO 1 /**< Application's BLE observer priority. You shouldn't need to modify this value. */ + +#define SEL_RES_CASCADE_BIT_NUM 3 /**< Number of Cascade bit within SEL_RES byte. */ +#define SEL_RES_TAG_PLATFORM_MASK 0x60 /**< Mask of Tag Platform bit group within SEL_RES byte. */ +#define SEL_RES_TAG_PLATFORM_BIT_OFFSET 5 /**< Offset of the Tag Platform bit group within SEL_RES byte. */ + +#define TAG_TYPE_2_UID_LENGTH 7 /**< Length of the Tag's UID. */ +#define TAG_DATA_BUFFER_SIZE 1024 /**< Buffer size for data from a Tag. */ +#define TAG_DETECT_TIMEOUT 5000 /**< Timeout for function which searches for a tag. */ +#define TAG_TYPE_2_DATA_AREA_SIZE_OFFSET (T2T_CC_BLOCK_OFFSET + 2) /**< Offset of the byte with Tag's Data size. */ +#define TAG_TYPE_2_DATA_AREA_MULTIPLICATOR 8 /**< Multiplicator for a value stored in the Tag's Data size byte. */ +#define TAG_TYPE_2_FIRST_DATA_BLOCK_NUM (T2T_FIRST_DATA_BLOCK_OFFSET / T2T_BLOCK_SIZE) /**< First block number with Tag's Data. */ +#define TAG_TYPE_2_BLOCKS_PER_EXCHANGE (T2T_MAX_DATA_EXCHANGE / T2T_BLOCK_SIZE) /**< Number of blocks fetched in single Tag's Read command. */ + +#define DEVICE_NAME_BUFF_SIZE 30 /**< Size of the buffer used to store BLE device name. */ +#define BLE_GAP_ADDR_TYPE_INVALID 0x04 /**< Invalid address type. */ + +/** + * @brief Possible Tag Types. + */ +typedef enum +{ + NFC_T2T = 0x00, /**< Type 2 Tag Platform. */ + NFC_T4T = 0x01, /**< Type 4A Tag Platform. */ + NFC_TT_NOT_SUPPORTED /**< Tag Type not supported. */ +} nfc_tag_type_t; + +static ble_gap_addr_t m_device_addr; /**< Value acquired by NFC. Holds BLE address of peer device. */ +static ble_advdata_tk_value_t m_device_tk; /**< Value acquired by NFC. Holds Temporary Key of peer device. */ + +static volatile bool m_tag_match = false; /**< Flag indicating that the read tag has valid Connection Handover information. */ +static bool m_read_tag = false; /**< Flag indicating that NFC reader is turned on. */ + +static ble_gap_lesc_oob_data_t m_ble_lesc_oob_peer_data; /**< LESC OOB pairing data. */ + +__ALIGN(4) static ble_gap_lesc_p256_pk_t m_lesc_pk; /**< LESC ECC Public Key. */ +__ALIGN(4) static ble_gap_lesc_p256_pk_t m_lesc_sk; /**< LESC ECC Secret Key. */ +__ALIGN(4) static ble_gap_lesc_dhkey_t m_lesc_dhkey; /**< LESC ECC DH Key. */ +__ALIGN(4) static ble_gap_lesc_p256_pk_t m_lesc_peer_pk; /**< LESC Peer ECC Public Key. */ + +static void ble_nfc_pair_handler(const ble_evt_t * const p_ble_evt, void * p_context); + +void nfc_pair_start(void) +{ + m_read_tag = true; +} + +void nfc_pair_stop(void) +{ + m_read_tag = false; +} + +void nfc_init(void) +{ + // Initialize encryption module with random number generator use. + ecc_init(true); + + ret_code_t err_code = adafruit_pn532_init(false); + APP_ERROR_CHECK(err_code); + + err_code = nrf_drv_rng_init(NULL); + APP_ERROR_CHECK(err_code); + + // Generate Diffie-Hellman pairing keys. + err_code = ecc_p256_keypair_gen(m_lesc_sk.pk, m_lesc_pk.pk); + APP_ERROR_CHECK(err_code); + + // Update Peer Manager with new LESC keys. + err_code = pm_lesc_public_key_set(&m_lesc_pk); + APP_ERROR_CHECK(err_code); + + // Register handler for BLE events. + NRF_SDH_BLE_OBSERVER(m_ble_observer, NFC_BLE_PAIR_OBSERVER_PRIO, ble_nfc_pair_handler, NULL); +} + +/** + * @brief Function for identifying Tag Platform Type. + */ +static nfc_tag_type_t tag_type_identify(uint8_t sel_res) +{ + uint8_t platform_config; + + // Check if Cascade bit in SEL_RES response is cleared. Cleared bit indicates that NFCID1 complete. + if (!IS_SET(sel_res, SEL_RES_CASCADE_BIT_NUM)) + { + // Extract platform configuration from SEL_RES response. + platform_config = (sel_res & SEL_RES_TAG_PLATFORM_MASK) >> SEL_RES_TAG_PLATFORM_BIT_OFFSET; + if (platform_config < NFC_TT_NOT_SUPPORTED) + { + return (nfc_tag_type_t) platform_config; + } + } + + return NFC_TT_NOT_SUPPORTED; +} + +/** + * @brief Function for reading data from a Tag. + * + * @details This function waits for a Tag to appear in the field. When a Tag is detected, all of the pages + * within a Tag are read. + */ +ret_code_t tag_data_read(uint8_t * buffer, uint32_t buffer_size) +{ + ret_code_t err_code; + nfc_a_tag_info tag_info; + uint8_t block_num = 0; + + // Not enough size in the buffer to read a tag header. + if (buffer_size < T2T_FIRST_DATA_BLOCK_OFFSET) + { + return NRF_ERROR_NO_MEM; + } + + // Detect a NFC-A Tag in the field and initiate a communication. This function activates + // the NFC RF field. If a Tag is present, basic information about detected Tag is returned + // in tag info structure. + err_code = adafruit_pn532_nfc_a_target_init(&tag_info, TAG_DETECT_TIMEOUT); + VERIFY_FALSE(err_code != NRF_SUCCESS, NRF_ERROR_NOT_FOUND); + + nfc_tag_type_t tag_type = tag_type_identify(tag_info.sel_res); + VERIFY_FALSE(tag_type != NFC_T2T, NRF_ERROR_NOT_SUPPORTED); + + // Read pages 0 - 3 to get the header information. + err_code = adafruit_pn532_tag2_read(block_num, buffer); + if (err_code) + { + NRF_LOG_INFO("Failed to read blocks: %d-%d", block_num, + block_num + T2T_END_PAGE_OFFSET); + return NRF_ERROR_INTERNAL; + } + + uint16_t data_bytes_in_tag = TAG_TYPE_2_DATA_AREA_MULTIPLICATOR * + buffer[TAG_TYPE_2_DATA_AREA_SIZE_OFFSET]; + + if (data_bytes_in_tag + T2T_FIRST_DATA_BLOCK_OFFSET > buffer_size) + { + return NRF_ERROR_NO_MEM; + } + + uint8_t blocks_to_read = data_bytes_in_tag / T2T_BLOCK_SIZE; + + for (block_num = TAG_TYPE_2_FIRST_DATA_BLOCK_NUM; + block_num < blocks_to_read; + block_num += TAG_TYPE_2_BLOCKS_PER_EXCHANGE) + { + uint16_t offset_for_block = T2T_BLOCK_SIZE * block_num; + + err_code = adafruit_pn532_tag2_read(block_num, buffer + offset_for_block); + if (err_code) + { + NRF_LOG_INFO("Failed to read blocks: %d-%d", + block_num, + block_num + T2T_END_PAGE_OFFSET); + return NRF_ERROR_INTERNAL; + } + } + + return NRF_SUCCESS; +} + +/** + * @brief Function used to indicate that the read Connection Handover NDEF Message is valid. + */ +__STATIC_INLINE void nfc_oob_pairing_tag_appoint(void) +{ + m_tag_match = true; +} + +void nfc_oob_pairing_tag_invalidate(void) +{ + m_device_addr.addr_type = BLE_GAP_ADDR_TYPE_INVALID; + m_tag_match = false; +} + +/** + * @brief Function for storing BLE device address, Temporary Key and LESC OOB data in static memory. + */ +__STATIC_INLINE void nfc_essential_pairing_data_copy(nfc_ble_oob_pairing_data_t * p_pairing_data) +{ + if (p_pairing_data->p_device_addr != NULL) + { + memcpy(&m_device_addr, p_pairing_data->p_device_addr, sizeof(ble_gap_addr_t)); + } + + if (p_pairing_data->p_tk_value != NULL) + { + memcpy(&m_device_tk, p_pairing_data->p_tk_value, sizeof(ble_advdata_tk_value_t)); + } + + if (p_pairing_data->p_lesc_confirm_value != NULL) + { + memcpy(m_ble_lesc_oob_peer_data.c, + p_pairing_data->p_lesc_confirm_value, + sizeof(m_ble_lesc_oob_peer_data.c)); + } + + if (p_pairing_data->p_lesc_random_value != NULL) + { + memcpy(m_ble_lesc_oob_peer_data.r, + p_pairing_data->p_lesc_random_value, + sizeof(m_ble_lesc_oob_peer_data.r)); + } + + if (p_pairing_data->p_device_addr != NULL) + { + memcpy(&m_ble_lesc_oob_peer_data.addr, + p_pairing_data->p_device_addr, + sizeof(ble_gap_addr_t)); + } +} + +/** + * @brief Function for analyzing Connection Handover NDEF message. + */ +void ch_ndef_msg_handle(nfc_ndef_msg_desc_t * p_ch_msg_desc) +{ + nfc_ble_oob_pairing_data_t le_oob_record_pairing_data; + uint8_t device_name[DEVICE_NAME_BUFF_SIZE]; + ble_advdata_tk_value_t device_tk; + ble_gap_lesc_oob_data_t device_lesc_data; + + for (uint8_t i = 0; i < p_ch_msg_desc->record_count; i++) + { + le_oob_record_pairing_data.device_name.p_name = device_name; + le_oob_record_pairing_data.device_name.len = sizeof(device_name); + le_oob_record_pairing_data.p_device_addr = &device_lesc_data.addr; + le_oob_record_pairing_data.p_tk_value = &device_tk; + le_oob_record_pairing_data.p_lesc_confirm_value = (uint8_t *)device_lesc_data.c; + le_oob_record_pairing_data.p_lesc_random_value = (uint8_t *)device_lesc_data.r; + + // Parse an NDEF message, assuming it is a Connection Handover message. + ret_code_t err_code = nfc_le_oob_rec_parse(p_ch_msg_desc->pp_record[i], + &le_oob_record_pairing_data); + if (err_code == NRF_SUCCESS) + { + nfc_oob_data_printout(&le_oob_record_pairing_data); + + int mem_diff = memcmp(&m_device_addr, + le_oob_record_pairing_data.p_device_addr, + sizeof(ble_gap_addr_t)); + + if (mem_diff != 0) // NFC Tag of the currently disconnected peripheral has been read. + { + if (m_device_addr.addr_type != BLE_GAP_ADDR_TYPE_INVALID) + { + // Terminate the current connection, so the new peripheral will be able to connect. + ble_disconnect(); + while (m_tag_match){}; + } + nfc_essential_pairing_data_copy(&le_oob_record_pairing_data); + nfc_oob_pairing_tag_appoint(); + } + else // NFC Tag of the currently connected peripheral has been read. + { + ble_disconnect(); + while (m_tag_match){}; + } + break; + } + } +} + +/** + * @brief Function for analyzing NDEF data from a TLV block. + * + * @details This function checks if a TLV block is in NDEF format. If an NDEF block is detected, + * the NDEF data is parsed and printed. + */ +void ndef_data_analyze(tlv_block_t * p_tlv_block) +{ + uint8_t desc_buf[NFC_NDEF_PARSER_REQIRED_MEMO_SIZE_CALC(10)]; + uint32_t nfc_data_len; + uint32_t desc_buf_len = sizeof(desc_buf); + ret_code_t ret_code; + + if (p_tlv_block->tag == TLV_NDEF_MESSAGE) + { + nfc_data_len = p_tlv_block->length; + + ret_code = ndef_msg_parser(desc_buf, + &desc_buf_len, + p_tlv_block->p_value, + &nfc_data_len); + ndef_msg_printout((nfc_ndef_msg_desc_t *) desc_buf); + + if (ret_code != NRF_SUCCESS) + { + NRF_LOG_INFO("Error during parsing a NDEF message."); + } + else + { + ch_ndef_msg_handle((nfc_ndef_msg_desc_t *) desc_buf); + } + } +} + +/** + * @brief Function for analyzing data from a Tag. + * + * @details This function parses content of a Tag and prints it out. + */ +void tag_data_analyze(uint8_t * buffer) +{ + ret_code_t err_code; + + // Static declaration of Type 2 Tag structure. Maximum of 10 TLV blocks can be read. + NFC_TYPE_2_TAG_DESC_DEF(test_1, 10); + type_2_tag_t * test_type_2_tag = &NFC_TYPE_2_TAG_DESC(test_1); + + err_code = type_2_tag_parse(test_type_2_tag, buffer); + if (err_code == NRF_ERROR_NO_MEM) + { + NRF_LOG_INFO("Not enough memory to read whole tag. Printing what've been read."); + } + else if (err_code != NRF_SUCCESS) + { + NRF_LOG_INFO("Error during parsing a tag. Printing what could've been read."); + } + + NRF_LOG_RAW_INFO("\r\n"); + type_2_tag_printout(test_type_2_tag); + NRF_LOG_RAW_INFO("\r\n"); + + tlv_block_t * p_tlv_block = test_type_2_tag->p_tlv_block_array; + uint32_t i; + + for (i = 0; i < test_type_2_tag->tlv_count; i++) + { + ndef_data_analyze(p_tlv_block); + p_tlv_block++; + } +} + +void nfc_tag_process(void) +{ + ret_code_t err_code; + + if (m_read_tag) + { + // Buffer for tag data. + static uint8_t tag_data[TAG_DATA_BUFFER_SIZE]; + + err_code = tag_data_read(tag_data, TAG_DATA_BUFFER_SIZE); + switch (err_code) + { + case NRF_SUCCESS: + tag_data_analyze(tag_data); + nfc_pair_stop(); + scan_start(); + break; + + case NRF_ERROR_NO_MEM: + NRF_LOG_INFO("Declared buffer is to small to store tag data."); + break; + + case NRF_ERROR_NOT_FOUND: + NRF_LOG_INFO("No Tag found."); + break; + + case NRF_ERROR_NOT_SUPPORTED: + NRF_LOG_INFO("Tag not supported."); + break; + + default: + NRF_LOG_INFO("Error during tag read."); + err_code = adafruit_pn532_field_off(); + APP_ERROR_CHECK(err_code); + break; + } + } +} + +bool nfc_oob_pairing_tag_match(ble_gap_addr_t const * const p_peer_addr) +{ + if (m_tag_match) + { + if (memcmp(p_peer_addr->addr, m_device_addr.addr, BLE_GAP_ADDR_LEN) == 0) + { + return true; + } + } + return false; +} + +/** + * @brief Function used for acquiring Temporary Key value. + * + * @param[out] pp_tk_value Pointer to pointer to the Temporary Key Value. + * + * @retval NRF_SUCCESS If the Temporary Key was found. + * @retval NRF_ERROR_NOT_FOUND Otherwise. + */ +ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value) +{ + if (m_tag_match) + { + *pp_tk_value = &m_device_tk; + return NRF_SUCCESS; + } + else + { + return NRF_ERROR_NOT_FOUND; + } +} + +/** + * @brief Function for handling NFC pairing BLE events. + * + * @details Handles authentication events, replying with OOB data. + * + * @param[in] p_ble_evt Bluetooth stack event. + * @param[in] p_context Unused. + */ +static void ble_nfc_pair_handler(const ble_evt_t * const p_ble_evt, void * p_context) +{ + ret_code_t err_code; + + const ble_gap_evt_t * const p_gap_evt = &p_ble_evt->evt.gap_evt; + + switch (p_ble_evt->header.evt_id) + { + // Upon authentication key request, reply with Temporary Key that was read from the NFC tag. + case BLE_GAP_EVT_AUTH_KEY_REQUEST: + { + NRF_LOG_INFO("BLE_GAP_EVT_AUTH_KEY_REQUEST"); + + ble_advdata_tk_value_t* oob_key; + err_code = nfc_tk_value_get(&oob_key); + APP_ERROR_CHECK(err_code); + + err_code = sd_ble_gap_auth_key_reply(p_gap_evt->conn_handle, + BLE_GAP_AUTH_KEY_TYPE_OOB, + oob_key->tk); + APP_ERROR_CHECK(err_code); + } break; + + // Upon LESC Diffie_Hellman key request, reply with key computed from device secret key and peer public key. + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + { + NRF_LOG_INFO("BLE_GAP_EVT_LESC_DHKEY_REQUEST"); + + uint16_t conn_handle = ble_get_conn_handle(); + + // If LESC OOB pairing is on, perform authentication with OOB data. + if (p_ble_evt->evt.gap_evt.params.lesc_dhkey_request.oobd_req) + { + err_code = sd_ble_gap_lesc_oob_data_set(conn_handle, + NULL, + &m_ble_lesc_oob_peer_data); + APP_ERROR_CHECK(err_code); + } + + // Buffer peer Public Key because ECC module arguments must be word aligned. + memcpy(&m_lesc_peer_pk.pk[0], + &p_ble_evt->evt.gap_evt.params.lesc_dhkey_request.p_pk_peer->pk[0], + BLE_GAP_LESC_P256_PK_LEN); + + // Compute D-H key. + err_code = ecc_p256_shared_secret_compute(&m_lesc_sk.pk[0], + &m_lesc_peer_pk.pk[0], + &m_lesc_dhkey.key[0]); + APP_ERROR_CHECK(err_code); + + // Reply with obtained result. + err_code = sd_ble_gap_lesc_dhkey_reply(conn_handle, &m_lesc_dhkey); + APP_ERROR_CHECK(err_code); + } break; + } +} + |