diff --git a/nimble/controller/pkg.yml b/nimble/controller/pkg.yml index 2f22e3ebf5..e5ba7b600c 100644 --- a/nimble/controller/pkg.yml +++ b/nimble/controller/pkg.yml @@ -42,7 +42,14 @@ pkg.deps: - nimble - nimble/transport +pkg.deps.TEST: + - "@apache-mynewt-core/crypto/mbedtls" + pkg.init: ble_ll_init: - $before:ble_transport_hs_init - $before:ble_transport_ll_init + +pkg.cflags.TEST: + - -Irepos/mbedtls/include + - -Irepos/include/mbedtls diff --git a/nimble/controller/src/ble_ll_cs_drbg.c b/nimble/controller/src/ble_ll_cs_drbg.c new file mode 100644 index 0000000000..0f40cf9f73 --- /dev/null +++ b/nimble/controller/src/ble_ll_cs_drbg.c @@ -0,0 +1,686 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#if MYNEWT_VAL(BLE_LL_CHANNEL_SOUNDING) +#include +#include +#include +#include "nimble/ble.h" +#include "mbedtls/aes.h" +#include "ble_ll_cs_drbg_priv.h" + +static const uint8_t rtt_seq_len[] = {0, 4, 12, 4, 8, 12, 16}; + +/** + * Security function e generates 128-bit encrypted_data from a 128-bit key + * and 128-bit data using the AES-128-bit block cypher. + */ +int +ble_ll_cs_drbg_e(const uint8_t *key, const uint8_t *data, uint8_t *out_data) +{ + struct ble_encryption_block ecb; + int rc = 0; + + /* The cryptographic function uses the leftmost to rightmost + * representation (MSO to LSO). + */ + swap_buf(ecb.key, key, BLE_ENC_BLOCK_SIZE); + swap_buf(ecb.plain_text, data, BLE_ENC_BLOCK_SIZE); + +#if BABBLESIM || MYNEWT_VAL(SELFTEST) + /* Use software to encrypt the data */ + mbedtls_aes_context aes_ctx; + mbedtls_aes_init(&aes_ctx); + mbedtls_aes_setkey_enc(&aes_ctx, ecb.key, 16 * 8); + rc = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, ecb.plain_text, ecb.cipher_text); + mbedtls_aes_free(&aes_ctx); +#else + /* Use hardware to encrypt the data */ + rc = ble_hw_encrypt_block(&ecb); +#endif + + if (!rc) { + swap_buf(out_data, ecb.cipher_text, BLE_ENC_BLOCK_SIZE); + } else { + rc = -1; + } + + return rc; +} + +/** + * DRBG chain function f7. + * - k - 128-bit key + * - in - an input bit string whose length is a multiple of 128 bits and + * generates an output that is 128 bits long using a cipher block + * chaining technique. + * - out - processed bit string + */ +int +ble_ll_cs_drbg_f7(const uint8_t *k, const uint8_t *in, uint8_t len, uint8_t *out) +{ + int rc; + int i; + const uint64_t *block; + uint64_t *hout = (uint64_t *)out; + + memset(hout, 0, 16); + + /* Starting with the leftmost bits (MSO) of input_bit_string, split into + * 128-bit blocks + */ + for (i = len - 16; i >= 0; i -= 16) { + block = (uint64_t *)&in[i]; + /* XOR a 128-bit block in two steps */ + *hout ^= *block; + *(hout + 1) ^= *(block + 1); + + rc = ble_ll_cs_drbg_e(k, out, out); + if (rc) { + break; + } + } + + return rc; +} + +/** + * DRBG derivation function f8. + * - input - 320-bit input bit string + * - sm - output, generated 256-bit seed material (SM) + */ +int +ble_ll_cs_drbg_f8(const uint8_t *input, uint8_t *sm) +{ + int rc; + uint8_t k[16] = {0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; + uint8_t k2[16] = {0}; + uint8_t x[16] = {0}; + /* buf contains V || S */ + uint8_t buf[80] = {0}; + uint8_t *s = buf; + uint8_t *v = buf + 64; + + /* S = 0x0000002800000020 || input_bit_string || 0x80 || + * 0x000000000000000000000000000000 + */ + s[15] = 0x80; + memcpy(s + 16, input, 40); + put_le64(s + 56, 0x0000002800000020); + + /* K2 = f7( K, V || S ) */ + rc = ble_ll_cs_drbg_f7(k, buf, 80, k2); + if (rc) { + return rc; + } + + /* V = 0x00000001000000000000000000000000 */ + v[12] = 0x01; + + /* X = f7( K, V || S ) */ + rc = ble_ll_cs_drbg_f7(k, buf, 80, x); + if (rc) { + return rc; + } + + /* Calculate the most significant part of SM: + * SM = e( K2, X ) + */ + rc = ble_ll_cs_drbg_e(k2, x, sm + 16); + if (rc) { + return rc; + } + + /* Calculate the least significant part of SM and concatenate + * both parts: + * SM = SM || e( K2, SM ) + */ + rc = ble_ll_cs_drbg_e(k2, sm + 16, sm); + + return rc; +} + +/** + * DRBG update function f9 is used to update and refresh a DRBG 128-bit + * temporal key K and a 128-bit nonce vector V using a 256-bit seed material (SM) + * that may carry fresh entropy. The SM value may also be 0 if f9 is called for + * backtracking purposes. + * - sm - 256-bit seed material + * - k_in - 128-bit key + * - v_in - 128-bit nonce vector + */ +int +ble_ll_cs_drbg_f9(const uint8_t *sm, uint8_t *k, uint8_t *v) +{ + int rc; + uint8_t x[32] = {0}; + uint64_t *x_p = (uint64_t *)x; + uint64_t *sm_p = (uint64_t *)sm; + + /* V = V[127:8] || (( V[7:0] + 1 ) mod 2^8) */ + v[0]++; + rc = ble_ll_cs_drbg_e(k, v, x + 16); + if (rc) { + return rc; + } + + v[0]++; + /* Again V = V[127:8] || (( V[7:0] + 1 ) mod 2^8) */ + rc = ble_ll_cs_drbg_e(k, v, x); + if (rc) { + return rc; + } + + /* X = X ⊕ SM */ + x_p[0] ^= sm_p[0]; + x_p[1] ^= sm_p[1]; + x_p[2] ^= sm_p[2]; + x_p[3] ^= sm_p[3]; + + memcpy(v, x, 16); + memcpy(k, x + 16, 16); + + return 0; +} + +/** + * DRBG instantiation function h9. + * - iv - 128-bit initialization vector (CS_IV) + * - in - 64-bit instantiation nonce (CS_IN) + * - pv - 128-bit personalization vector (CS_PV) + * - key - output, 128-bit temporal key (K_DRBG) + * - nonce_v - output, 128-bit nonce vector (V_DRBG) + */ +int +ble_ll_cs_drbg_h9(const uint8_t *iv, const uint8_t *in, const uint8_t *pv, + uint8_t *key, uint8_t *nonce_v) +{ + int rc; + uint8_t input_bit_string[40] = {0}; + uint8_t sm[32] = {0}; + + /* 320-bit input bit string created from concatenated vectors + * CS_IV || CS_IN || CS_PV + */ + memcpy(input_bit_string, pv, 16); + memcpy(input_bit_string + 16, in, 8); + memcpy(input_bit_string + 24, iv, 16); + + /* Generate seed material (SM) */ + rc = ble_ll_cs_drbg_f8(input_bit_string, sm); + if (rc) { + return rc; + } + + /* Generate K_DRBG and V_DRBG */ + memset(key, 0, 16); + memset(nonce_v, 0, 16); + rc = ble_ll_cs_drbg_f9(sm, key, nonce_v); + + return rc; +} + +/** + * Random bit generation function CS_DRBG + * - transaction_id - CSTransactionID, + * - drbg_ctx - the drbg context, already inited with keys, + * - output - output buffer, + * - len - number of bytes to be generated. + */ +int +ble_ll_cs_drbg_rand(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t transaction_id, + uint8_t *output, uint8_t len) +{ + int rc; + uint8_t rand_len = 0; + uint8_t nonce[16]; + struct ble_ll_cs_transaction_cache *cache = &drbg_ctx->t_cache[transaction_id]; + + /* Set the fixed values of the DRGB nonce */ + memcpy(nonce, drbg_ctx->nonce_v, sizeof(nonce)); + /* Set the Transaction_Counter */ + if (cache->last_step_count != step_count) { + cache->transaction_counter = 0; + cache->last_step_count = step_count; + } + nonce[0] += cache->transaction_counter; + /* Set the Transaction_Identifier */ + nonce[1] += transaction_id; + /* Set the CS Step_Counter */ + put_le16(&nonce[2], step_count + get_le16(&nonce[2])); + + while (len > 0) { + if (cache->free_bytes > 0) { + /* Use bytes from previous DRBG invocation */ + + if (len < cache->free_bytes) { + rand_len = len; + } else { + rand_len = cache->free_bytes; + } + + cache->free_bytes -= rand_len; + /* [0] is LSO, [15] is MSO. Return cached bytes starting from MSO. */ + memcpy(output, cache->random_bytes + cache->free_bytes, rand_len); + + len -= rand_len; + output += rand_len; + } else { + /* Invoke CS_DRBG to get fresh 128-bit sequence */ + rc = ble_ll_cs_drbg_e(drbg_ctx->key, nonce, cache->random_bytes); + if (rc) { + return rc; + } + + cache->free_bytes = sizeof(cache->random_bytes); + /* Increment the transaction counter */ + ++nonce[0]; + ++cache->transaction_counter; + } + } + + return 0; +} + +/** Channel Sounding random number generation function hr1 */ +int +ble_ll_cs_drbg_rand_hr1(struct ble_ll_cs_drbg_ctx *drbg_ctx, uint16_t step_count, + uint8_t transaction_id, uint8_t r, uint8_t *r_out) +{ + int rc; + uint16_t t_rand; + uint8_t random_bits; + + if (r <= 1) { + *r_out = 0; + + return 0; + } + + rc = ble_ll_cs_drbg_rand(drbg_ctx, step_count, + transaction_id, &random_bits, 1); + if (rc) { + return rc; + } + + t_rand = r * random_bits; + + if ((t_rand & 0xFF) < (256 % r)) { + rc = ble_ll_cs_drbg_rand(drbg_ctx, step_count, + transaction_id, &random_bits, 1); + *r_out = ((256 * random_bits * r) + t_rand) / 65536; + } else { + *r_out = t_rand / 256; + } + + return rc; +} + +int +ble_ll_cs_drbg_shuffle_cr1(struct ble_ll_cs_drbg_ctx *drbg_ctx, uint16_t step_count, + uint8_t transaction_id, uint8_t *channel_array, + uint8_t *shuffled_array, uint8_t len) +{ + int rc; + uint8_t i, j; + + for (i = 0; i < len; ++i) { + rc = ble_ll_cs_drbg_rand_hr1(drbg_ctx, step_count, transaction_id, i + 1, &j); + if (rc) { + return rc; + } + + if (i != j) { + shuffled_array[i] = shuffled_array[j]; + } + + shuffled_array[j] = channel_array[i]; + } + + return 0; +} + +static int +cs_autocorrelation_score(uint32_t sequence) +{ + int i, k, score = 0; + uint32_t c, s; + + for (k = 1; k <= 3; ++k) { + c = 0; + s = sequence; + for (i = 1; i <= 32 - k; ++i) { + c += (s & 1) ^ ((s >> k) & 1); + s >>= 1; + } + score += abs(2 * c - (32 - k)); + } + + return score; +} + +int +ble_ll_cs_drbg_generate_aa(struct ble_ll_cs_drbg_ctx *drbg_ctx, uint16_t step_count, + uint32_t *initiator_aa, uint32_t *reflector_aa) +{ + int rc; + uint8_t buf[16]; + uint32_t s0, s1, s2, s3; + + rc = ble_ll_cs_drbg_rand(drbg_ctx, step_count, + BLE_LL_CS_DRBG_ACCESS_ADDRESS, + buf, sizeof(buf)); + + if (rc) { + return rc; + } + + /* The buf[15] is the first generated octet */ + s0 = get_le32(&buf[12]); + s1 = get_le32(&buf[8]); + s2 = get_le32(&buf[4]); + s3 = get_le32(&buf[0]); + + /* The sequence with the lower autocorrelation score is selected + * as the CS Access Address. See 2.2.1 Channel Sounding Access Address + * selection rules. + */ + if (cs_autocorrelation_score(s0) < cs_autocorrelation_score(s1)) { + *initiator_aa = s0; + } else { + *initiator_aa = s1; + } + + if (cs_autocorrelation_score(s2) < cs_autocorrelation_score(s3)) { + *reflector_aa = s2; + } else { + *reflector_aa = s3; + } + + return 0; +} + +int +ble_ll_cs_drbg_rand_marker_position(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t rtt_type, + uint8_t *position1, uint8_t *position2) +{ + int rc; + uint8_t rand_range; + + if (rtt_type == BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE) { + rand_range = 29; + } else { /* BLE_LL_CS_RTT_96_BIT_SOUNDING_SEQUENCE */ + rand_range = 64; + } + + rc = ble_ll_cs_drbg_rand_hr1(drbg_ctx, step_count, + BLE_LL_CS_DRBG_SEQ_MARKER_POSITION, + rand_range, position1); + if (rc) { + return -1; + } + + if (rtt_type == BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE) { + *position2 = 0xFF; + + return 0; + } + + rc = ble_ll_cs_drbg_rand_hr1(drbg_ctx, step_count, + BLE_LL_CS_DRBG_SEQ_MARKER_POSITION, + 75, position2); + if (rc) { + return -1; + } + + *position2 += 67; + if (*position2 > 92) { + /* Omit the second marker */ + *position2 = 0xFF; + } + + return 0; +} + +int +ble_ll_cs_drbg_rand_marker_selection(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, uint8_t *marker_selection) +{ + int rc; + + if (drbg_ctx->marker_selection_free_bits == 0) { + rc = ble_ll_cs_drbg_rand(drbg_ctx, step_count, + BLE_LL_CS_DRBG_SEQ_MARKER_SIGNAL, + &drbg_ctx->marker_selection_cache, 1); + if (rc) { + return rc; + } + + drbg_ctx->marker_selection_free_bits = 8; + } + + *marker_selection = drbg_ctx->marker_selection_cache & 0x80; + drbg_ctx->marker_selection_cache <<= 1; + --drbg_ctx->marker_selection_free_bits; + + return 0; +} + +int +ble_ll_cs_drbg_rand_main_mode_steps(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, + uint8_t main_mode_min_steps, + uint8_t main_mode_max_steps, + uint8_t *main_mode_steps) +{ + int rc; + uint8_t r; + uint8_t r_out; + + r = main_mode_max_steps - main_mode_min_steps + 1; + rc = ble_ll_cs_drbg_rand_hr1(drbg_ctx, step_count, + BLE_LL_CS_DRBG_SUBEVT_SUBMODE, + r, &r_out); + if (rc) { + return rc; + } + + *main_mode_steps = r_out + main_mode_min_steps; + + return 0; +} + +static int +ble_ll_cs_drbg_apply_marker_signal(struct ble_ll_cs_drbg_ctx *drbg_ctx, uint8_t step_count, + uint8_t *buf, uint8_t position) +{ + int rc; + uint16_t *byte_ptr; + uint16_t marker_signal; + uint8_t marker_selection; + uint8_t byte_id = 0; + uint8_t bit_offset = 0; + + rc = ble_ll_cs_drbg_rand_marker_selection(drbg_ctx, step_count, &marker_selection); + if (rc) { + return rc; + } + + if (marker_selection) { + /* '0011' in transmission order */ + marker_signal = 0b1100; + } else { + /* '1100' in transmission order */ + marker_signal = 0b0011; + } + + byte_id = position / 8; + byte_ptr = (uint16_t *) &buf[byte_id]; + bit_offset = position % 8; + *byte_ptr &= ~(0xF << bit_offset); + *byte_ptr |= ~(marker_signal << bit_offset); + + return 0; +} + +static int +ble_ll_cs_generate_sounding_sequence(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, uint8_t rtt_type, + uint8_t *buf, uint8_t sequence_len) +{ + int rc; + uint8_t i; + uint8_t position1; + uint8_t position2; + + for (i = 0; i < sequence_len; ++i) { + buf[i] = 0b10101010; + } + + rc = ble_ll_cs_drbg_rand_marker_position(drbg_ctx, step_count, rtt_type, + &position1, &position2); + if (rc) { + return rc; + } + + rc = ble_ll_cs_drbg_apply_marker_signal(drbg_ctx, step_count, buf, position1); + if (rc) { + return rc; + } + + if (position2 != 0xFF) { + rc = ble_ll_cs_drbg_apply_marker_signal(drbg_ctx, step_count, buf, position2); + } + + return rc; +} + +int +ble_ll_cs_drbg_generate_sync_sequence(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, + uint8_t rtt_type, + uint8_t *buf, + uint8_t *sequence_len) +{ + int rc = -1; + + *sequence_len = rtt_seq_len[rtt_type]; + + switch (rtt_type) { + case BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE: + rc = ble_ll_cs_generate_sounding_sequence(drbg_ctx, step_count, rtt_type, + buf, *sequence_len); + break; + case BLE_LL_CS_RTT_96_BIT_SOUNDING_SEQUENCE: + rc = ble_ll_cs_generate_sounding_sequence(drbg_ctx, step_count, rtt_type, + buf, *sequence_len); + break; + case BLE_LL_CS_RTT_32_BIT_RANDOM_SEQUENCE: + case BLE_LL_CS_RTT_64_BIT_RANDOM_SEQUENCE: + case BLE_LL_CS_RTT_96_BIT_RANDOM_SEQUENCE: + case BLE_LL_CS_RTT_128_BIT_RANDOM_SEQUENCE: + rc = ble_ll_cs_drbg_rand(drbg_ctx, step_count, + BLE_LL_CS_DRBG_RAND_SEQ_GENERATION, + buf, *sequence_len); + break; + default: + break; + } + + return rc; +} + +int +ble_ll_cs_drbg_rand_tone_ext_presence(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, uint8_t *presence) +{ + int rc; + + if (drbg_ctx->tone_ext_presence_free_bits == 0) { + rc = ble_ll_cs_drbg_rand(drbg_ctx, step_count, + BLE_LL_CS_DRBG_T_PM_TONE_SLOT_PRESENCE, + &drbg_ctx->tone_ext_presence_cache, 1); + if (rc) { + return rc; + } + + drbg_ctx->tone_ext_presence_free_bits = 8; + } + + *presence = drbg_ctx->tone_ext_presence_cache & 0x80 ? 1 : 0; + drbg_ctx->tone_ext_presence_cache <<= 1; + --drbg_ctx->tone_ext_presence_free_bits; + + return 0; +} + +int +ble_ll_cs_drbg_rand_antenna_path_perm_id(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t n_ap, + uint8_t *ap_id) +{ + int rc; + uint8_t i; + uint8_t n_ap_f = 0; + + if (n_ap <= 1) { + *ap_id = 0; + + return 0; + } + + assert(n_ap <= 4); + + for (i = 1; i <= n_ap; ++i) { + n_ap_f *= i; + } + + rc = ble_ll_cs_drbg_rand_hr1(drbg_ctx, step_count, + BLE_LL_CS_DRBG_ANTENNA_PATH_PERMUTATION, + n_ap_f, ap_id); + + return rc; +} + +void +ble_ll_cs_drbg_clear_cache(struct ble_ll_cs_drbg_ctx *drbg_ctx) +{ + memset(drbg_ctx->t_cache, 0, sizeof(drbg_ctx->t_cache)); + drbg_ctx->marker_selection_cache = 0; + drbg_ctx->marker_selection_free_bits = 0; +} + +int +ble_ll_cs_drbg_init(struct ble_ll_cs_drbg_ctx *drbg_ctx) +{ + /* Calculate temporal key K and nonce vector V */ + return ble_ll_cs_drbg_h9(drbg_ctx->iv, drbg_ctx->in, drbg_ctx->pv, + drbg_ctx->key, drbg_ctx->nonce_v); +} + +void +ble_ll_cs_drbg_free(struct ble_ll_cs_drbg_ctx *drbg_ctx) +{ + memset(drbg_ctx, 0, sizeof(*drbg_ctx)); +} +#endif /* BLE_LL_CHANNEL_SOUNDING */ diff --git a/nimble/controller/src/ble_ll_cs_drbg_priv.h b/nimble/controller/src/ble_ll_cs_drbg_priv.h new file mode 100644 index 0000000000..6e49e06789 --- /dev/null +++ b/nimble/controller/src/ble_ll_cs_drbg_priv.h @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_CS_DRBG_PRIV +#define H_BLE_LL_CS_DRBG_PRIV + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_LL_CS_DRBG_HOP_CHAN_NON_MODE0 (0x00) +#define BLE_LL_CS_DRBG_HOP_CHAN_MODE0 (0x01) +#define BLE_LL_CS_DRBG_SUBEVT_SUBMODE (0x02) +#define BLE_LL_CS_DRBG_T_PM_TONE_SLOT_PRESENCE (0x03) +#define BLE_LL_CS_DRBG_ANTENNA_PATH_PERMUTATION (0x04) +#define BLE_LL_CS_DRBG_ACCESS_ADDRESS (0x05) +#define BLE_LL_CS_DRBG_SEQ_MARKER_POSITION (0x06) +#define BLE_LL_CS_DRBG_SEQ_MARKER_SIGNAL (0x07) +#define BLE_LL_CS_DRBG_RAND_SEQ_GENERATION (0x08) +#define BLE_LL_CS_DRBG_BACKTRACKING_RESISTANCE (0x09) +#define BLE_LL_CS_DRBG_TRANSACTION_IDS_NUMBER (0x0a) + +#define BLE_LL_CS_RTT_AA_ONLY (0x00) +#define BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE (0x01) +#define BLE_LL_CS_RTT_96_BIT_SOUNDING_SEQUENCE (0x02) +#define BLE_LL_CS_RTT_32_BIT_RANDOM_SEQUENCE (0x03) +#define BLE_LL_CS_RTT_64_BIT_RANDOM_SEQUENCE (0x04) +#define BLE_LL_CS_RTT_96_BIT_RANDOM_SEQUENCE (0x05) +#define BLE_LL_CS_RTT_128_BIT_RANDOM_SEQUENCE (0x06) + +struct ble_ll_cs_transaction_cache { + uint16_t last_step_count; + /* 1-octet CSTransactionCounter per each CS Transaction ID. Should + * be reset each time the nonce V CS Step_Counter field is set to + * a new value. + */ + uint8_t transaction_counter; + /* Random bits cache */ + uint8_t random_bytes[16]; + /* The number of cached bytes that have been already used */ + uint8_t free_bytes; +}; + +/* DRBG context */ +struct ble_ll_cs_drbg_ctx { + /* Initialization vector, entropy input */ + uint8_t iv[16]; + /* Instantiation nonce */ + uint8_t in[8]; + /* Personalization vector/string */ + uint8_t pv[16]; + /* Temporal key K */ + uint8_t key[16]; + /* DRBG nonce/counter (V), the starting value from which the DRBG operates. + * Initialized once per LE Connection. + */ + uint8_t nonce_v[16]; + /* Cache bits generated with single DRBG transation */ + struct ble_ll_cs_transaction_cache t_cache[BLE_LL_CS_DRBG_TRANSACTION_IDS_NUMBER]; + + uint8_t marker_selection_free_bits; + uint8_t marker_selection_cache; + + uint8_t tone_ext_presence_free_bits; + uint8_t tone_ext_presence_cache; +}; + +int ble_ll_cs_drbg_e(const uint8_t *key, const uint8_t *data, uint8_t *out_data); +int ble_ll_cs_drbg_f7(const uint8_t *k, const uint8_t *in, uint8_t len, uint8_t *out); +int ble_ll_cs_drbg_f8(const uint8_t *input, uint8_t *sm); +int ble_ll_cs_drbg_f9(const uint8_t *sm, uint8_t *k, uint8_t *v); +int ble_ll_cs_drbg_h9(const uint8_t *iv, const uint8_t *in, const uint8_t *pv, + uint8_t *key, uint8_t *nonce_v); +int ble_ll_cs_drbg_rand(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t transaction_id, + uint8_t *output, uint8_t len); +int ble_ll_cs_drbg_rand_hr1(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t transaction_id, + uint8_t r, uint8_t *r_out); +int ble_ll_cs_drbg_shuffle_cr1(struct ble_ll_cs_drbg_ctx *drbg_ctx, uint16_t step_count, + uint8_t transaction_id, uint8_t *channel_array, + uint8_t *shuffled_array, uint8_t len); +int ble_ll_cs_drbg_generate_aa(struct ble_ll_cs_drbg_ctx *drbg_ctx, uint16_t step_count, + uint32_t *initiator_aa, uint32_t *reflector_aa); +int ble_ll_cs_drbg_rand_marker_position(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t rtt_type, + uint8_t *position1, uint8_t *position2); +int ble_ll_cs_drbg_rand_marker_selection(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, uint8_t *marker_selection); +int ble_ll_cs_drbg_rand_main_mode_steps(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, + uint8_t main_mode_min_steps, + uint8_t main_mode_max_steps, + uint8_t *main_mode_steps); +int ble_ll_cs_drbg_generate_sync_sequence(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, + uint8_t rtt_type, + uint8_t *buf, + uint8_t *sequence_len); +int ble_ll_cs_drbg_rand_antenna_path_perm_id(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint16_t step_count, uint8_t n_ap, + uint8_t *ap_id); +int ble_ll_cs_drbg_rand_tone_ext_presence(struct ble_ll_cs_drbg_ctx *drbg_ctx, + uint8_t step_count, uint8_t *presence); +int ble_ll_cs_drbg_init(struct ble_ll_cs_drbg_ctx *drbg_ctx); +void ble_ll_cs_drbg_free(struct ble_ll_cs_drbg_ctx *drbg_ctx); +void ble_ll_cs_drbg_clear_cache(struct ble_ll_cs_drbg_ctx *drbg_ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_CS_DRBG_PRIV */ diff --git a/nimble/controller/test/src/ble_ll_cs_drbg_test.c b/nimble/controller/test/src/ble_ll_cs_drbg_test.c new file mode 100644 index 0000000000..1edb920713 --- /dev/null +++ b/nimble/controller/test/src/ble_ll_cs_drbg_test.c @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "ble_ll_cs_drbg_priv.h" + +extern uint8_t g_ble_ll_cs_chan_indices[72]; + +static void +ble_ll_cs_drbg_e_test(void) +{ + uint8_t key[16] = {0}; + uint8_t data[16] = {0}; + uint8_t out[16] = {0}; + uint8_t expected_out[16] = {0}; + + /* Sample data from BT spec Vol 6, Part C, 1.1 Encrypt Command + * Swap because the copy-pasted strings are in leftmost (MSO) to rightmost + * (LSO) orientation. + */ + swap_buf(key, (uint8_t [16]) { + 0x4C, 0x68, 0x38, 0x41, 0x39, 0xF5, 0x74, 0xD8, + 0x36, 0xBC, 0xF3, 0x4E, 0x9D, 0xFB, 0x01, 0xBF + }, 16); + + swap_buf(data, (uint8_t [16]) { + 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, + 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1, 0x02, 0x13 + }, 16); + + swap_buf(expected_out, (uint8_t [16]) { + 0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e, + 0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66 + }, 16); + + ble_ll_cs_drbg_e(key, data, out); + TEST_ASSERT(memcmp(out, expected_out, sizeof(out)) == 0); +} + +static void +ble_ll_cs_drbg_f7_test(void) +{ + uint8_t v_s[80]; + uint8_t k[16]; + uint8_t k2[16] = {0}; + uint8_t x[16] = {0}; + uint8_t expected_k2[16] = {0}; + uint8_t expected_x[16] = {0}; + + /* Sample data from BT spec Vol 6, Part C, 7. Deterministic + * random bit generator sample data. + * Swap because the copy-pasted strings are in leftmost (MSO) + * to rightmost (LSO) orientation. + */ + swap_buf(k, (uint8_t [16]) { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, 16); + + swap_buf(v_s, (uint8_t [80]) { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, + 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9, + 0x3E, 0x7F, 0x51, 0x86, 0xE0, 0xCA, 0x0B, 0x3B, + 0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D, + 0xC9, 0x80, 0xDE, 0xDF, 0x98, 0x82, 0xED, 0x44, + 0x64, 0xA6, 0x74, 0x96, 0x78, 0x68, 0xF1, 0x43, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, 80); + + swap_buf(expected_k2, (uint8_t [16]) { + 0x8B, 0x2B, 0x06, 0xDC, 0x52, 0x2D, 0x3E, 0x0A, + 0xF0, 0xA5, 0x0C, 0xAF, 0x48, 0x10, 0xE0, 0x35 + }, 16); + + TEST_ASSERT(ble_ll_cs_drbg_f7(k, v_s, sizeof(v_s), k2) == 0); + TEST_ASSERT(memcmp(k2, expected_k2, sizeof(k2)) == 0); + + v_s[76] = 0x01; + swap_buf(expected_x, (uint8_t [16]) { + 0xA3, 0x4F, 0xBE, 0x57, 0xF8, 0xF9, 0x7E, 0x34, + 0x9D, 0x15, 0xA3, 0x76, 0x79, 0x60, 0x74, 0x64 + }, 16); + + TEST_ASSERT(ble_ll_cs_drbg_f7(k, v_s, sizeof(v_s), x) == 0); + TEST_ASSERT(memcmp(x, expected_x, sizeof(x)) == 0); +} + +static void +ble_ll_cs_drbg_f8_test(void) +{ + uint8_t input_bit_string[40] = {0}; + uint8_t expected_sm[32] = {0}; + uint8_t sm[32] = {0}; + + /* Sample data from BT spec Vol 6, Part C, 7. Deterministic + * random bit generator sample data. + * Swap because the copy-pasted strings are in leftmost (MSO) + * to rightmost (LSO) orientation. + */ + + /* 320-bit input bit string created from concatenated vectors + * CS_IV || CS_IN || CS_PV + */ + swap_buf(input_bit_string, (uint8_t [40]) { + 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9, + 0x3E, 0x7F, 0x51, 0x86, 0xE0, 0xCA, 0x0B, 0x3B, + 0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D, + 0xC9, 0x80, 0xDE, 0xDF, 0x98, 0x82, 0xED, 0x44, + 0x64, 0xA6, 0x74, 0x96, 0x78, 0x68, 0xF1, 0x43 + }, 40); + + swap_buf(expected_sm, (uint8_t [32]) { + 0xB6, 0x02, 0xB1, 0xB2, 0x8C, 0x6F, 0x0A, 0x3D, + 0xDA, 0xE6, 0x37, 0xB4, 0x84, 0x25, 0x08, 0x7D, + 0xDC, 0x18, 0x8C, 0x89, 0xA1, 0xB0, 0xCD, 0xFD, + 0xA1, 0xE8, 0xFC, 0x66, 0xC9, 0x99, 0x97, 0x50 + }, 32); + + TEST_ASSERT(ble_ll_cs_drbg_f8(input_bit_string, sm) == 0); + TEST_ASSERT(memcmp(sm, expected_sm, sizeof(sm)) == 0); +} + +static void +ble_ll_cs_drbg_f9_test(void) +{ + uint8_t sm[32] = {0}; + uint8_t k[16] = {0}; + uint8_t v[16] = {0}; + uint8_t expected_k[16] = {0}; + uint8_t expected_v[16] = {0}; + + /* First call to f9 from instantiation function h9, + * K and V vectors filled with zeros. + * + * Sample data from BT spec Vol 6, Part C, 7. Deterministic + * random bit generator sample data. + * Swap because the copy-pasted strings are in leftmost (MSO) + * to rightmost (LSO) orientation. + */ + + swap_buf(sm, (uint8_t [32]) { + 0xB6, 0x02, 0xB1, 0xB2, 0x8C, 0x6F, 0x0A, 0x3D, + 0xDA, 0xE6, 0x37, 0xB4, 0x84, 0x25, 0x08, 0x7D, + 0xDC, 0x18, 0x8C, 0x89, 0xA1, 0xB0, 0xCD, 0xFD, + 0xA1, 0xE8, 0xFC, 0x66, 0xC9, 0x99, 0x97, 0x50 + }, 32); + + swap_buf(expected_k, (uint8_t [16]) { + 0xEE, 0xE0, 0x4D, 0x7C, 0x76, 0x11, 0x3A, 0x5C, + 0xEC, 0x99, 0x2A, 0xE3, 0x20, 0xC2, 0x4D, 0x27 + }, 16); + + swap_buf(expected_v, (uint8_t [16]) { + 0xDF, 0x90, 0x56, 0x47, 0xC1, 0x06, 0x6E, 0x6F, + 0x52, 0xC0, 0x3E, 0xDF, 0xB8, 0x2B, 0x69, 0x28 + }, 16); + + TEST_ASSERT(ble_ll_cs_drbg_f9(sm, k, v) == 0); + TEST_ASSERT(memcmp(k, expected_k, sizeof(k)) == 0); + TEST_ASSERT(memcmp(v, expected_v, sizeof(v)) == 0); +} + +static void +cs_drbg_init(struct ble_ll_cs_drbg_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + + /* CS_IV = CS_IV_P || CS_IV_C */ + swap_buf(ctx->iv, (uint8_t [16]) { + 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9, + 0x3E, 0x7F, 0x51, 0x86, 0xE0, 0xCA, 0x0B, 0x3B + }, 16); + + /* CS_IN = CS_IN_P || CS_IN_C */ + swap_buf(ctx->in, (uint8_t [8]) { + 0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D + }, 8); + + /* CS_PV = CS_PV_P || CS_PV_C */ + swap_buf(ctx->pv, (uint8_t [16]) { + 0xC9, 0x80, 0xDE, 0xDF, 0x98, 0x82, 0xED, 0x44, + 0x64, 0xA6, 0x74, 0x96, 0x78, 0x68, 0xF1, 0x43 + }, 16); + + ble_ll_cs_drbg_init(ctx); +} + +static void +ble_ll_cs_drbg_rand_test(void) +{ + struct ble_ll_cs_drbg_ctx ctx; + uint8_t output[20] = {0}; + uint8_t expected_output[20] = {0}; + + /* Test if subsequent drgb generator calls returns expected bit sequences. */ + + cs_drbg_init(&ctx); + + /* First round - request full 128-bit batch */ + swap_buf(expected_output, (uint8_t [16]) { + 0x79, 0x74, 0x1F, 0xD1, 0x8F, 0x57, 0x7B, 0x45, + 0xD0, 0x9A, 0x66, 0x5A, 0x7F, 0x1F, 0x28, 0x58 + }, 16); + + TEST_ASSERT(ble_ll_cs_drbg_rand( + &ctx, 0x00, BLE_LL_CS_DRBG_HOP_CHAN_NON_MODE0, + output, 16) == 0); + TEST_ASSERT(memcmp(output, expected_output, 16) == 0); +} + +static void +ble_ll_cs_drbg_chan_selection_3b_test(void) +{ + struct ble_ll_cs_drbg_ctx ctx; + uint8_t filtered_channels[72] = {0}; + uint8_t shuffled_channels[72] = {0}; + uint8_t expected_shuffled_channels[19] = {0}; + + cs_drbg_init(&ctx); + + memcpy(filtered_channels, (uint8_t [19]) { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20 + }, 19); + + memcpy(expected_shuffled_channels, (uint8_t [19]) { + 11, 7, 14, 18, 9, 19, 10, 8, 5, 2, 4, 15, 16, 13, 12, 6, 17, 20, 3 + }, 19); + assert(ble_ll_cs_drbg_shuffle_cr1(&ctx, 0x00, BLE_LL_CS_DRBG_HOP_CHAN_MODE0, + filtered_channels, shuffled_channels, 19) == 0); + assert(memcmp(shuffled_channels, expected_shuffled_channels, 19) == 0); + + memcpy(expected_shuffled_channels, (uint8_t [19]) { + 6, 12, 5, 10, 3, 2, 18, 17, 16, 8, 11, 7, 19, 4, 13, 20, 9, 15, 14 + }, 19); + assert(ble_ll_cs_drbg_shuffle_cr1(&ctx, 0x03, BLE_LL_CS_DRBG_HOP_CHAN_NON_MODE0, + filtered_channels, shuffled_channels, 19) == 0); + assert(memcmp(shuffled_channels, expected_shuffled_channels, 19) == 0); +} + +static void +ble_ll_cs_drbg_generate_aa_test(void) +{ + struct ble_ll_cs_drbg_ctx ctx; + uint32_t initiator_aa; + uint32_t reflector_aa; + uint32_t expected_initiator_aa; + uint32_t expected_reflector_aa; + + cs_drbg_init(&ctx); + + /* Step 0 */ + assert(ble_ll_cs_drbg_generate_aa(&ctx, 0, &initiator_aa, &reflector_aa) == 0); + expected_initiator_aa = get_be32((uint8_t [4]) {0x6C, 0x37, 0x6A, 0xB8}); + expected_reflector_aa = get_be32((uint8_t [4]) {0xF0, 0x79, 0xBC, 0x3A}); + assert(initiator_aa == expected_initiator_aa); + assert(reflector_aa == expected_reflector_aa); + + /* Step 1 */ + assert(ble_ll_cs_drbg_generate_aa(&ctx, 1, &initiator_aa, &reflector_aa) == 0); + expected_initiator_aa = get_be32((uint8_t [4]) {0x01, 0x1C, 0xAE, 0x4E}); + expected_reflector_aa = get_be32((uint8_t [4]) {0xD0, 0x6A, 0xCD, 0xDA}); + assert(initiator_aa == expected_initiator_aa); + assert(reflector_aa == expected_reflector_aa); + + /* Step 2 */ + assert(ble_ll_cs_drbg_generate_aa(&ctx, 2, &initiator_aa, &reflector_aa) == 0); + expected_initiator_aa = get_be32((uint8_t [4]) {0x64, 0x06, 0x12, 0x14}); + expected_reflector_aa = get_be32((uint8_t [4]) {0x28, 0x94, 0x2F, 0x38}); + assert(initiator_aa == expected_initiator_aa); + assert(reflector_aa == expected_reflector_aa); + + /* Step 14 */ + assert(ble_ll_cs_drbg_generate_aa(&ctx, 14, &initiator_aa, &reflector_aa) == 0); + expected_initiator_aa = get_be32((uint8_t [4]) {0xF7, 0x21, 0x97, 0x86}); + expected_reflector_aa = get_be32((uint8_t [4]) {0x57, 0x17, 0x64, 0x70}); + assert(initiator_aa == expected_initiator_aa); + assert(reflector_aa == expected_reflector_aa); +} + +static void +ble_ll_cs_drbg_rand_marker_position_test(void) +{ + uint8_t position1; + uint8_t position2; + struct ble_ll_cs_drbg_ctx ctx; + + cs_drbg_init(&ctx); + + /* Step 9 */ + assert(ble_ll_cs_drbg_rand_marker_position( + &ctx, 9, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE, + &position1, &position2) == 0); + assert(position1 == 12 && position2 == 0xFF); + + assert(ble_ll_cs_drbg_rand_marker_position( + &ctx, 9, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE, + &position1, &position2) == 0); + assert(position1 == 4 && position2 == 0xFF); + + /* Step 14 */ + assert(ble_ll_cs_drbg_rand_marker_position( + &ctx, 14, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE, + &position1, &position2) == 0); + assert(position1 == 8 && position2 == 0xFF); + + assert(ble_ll_cs_drbg_rand_marker_position( + &ctx, 14, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE, + &position1, &position2) == 0); + assert(position1 == 11 && position2 == 0xFF); +} + +static void +ble_ll_cs_drbg_rand_marker_selection_test(void) +{ + uint8_t marker_selection; + struct ble_ll_cs_drbg_ctx ctx; + + cs_drbg_init(&ctx); + + /* Step 9 */ + assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 0x09, &marker_selection) == 0); + assert(marker_selection == 0x00); + + assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 0x09, &marker_selection) == 0); + assert(marker_selection == 0x80); + + memset(ctx.t_cache, 0, sizeof(ctx.t_cache)); + + /* Step 14 */ + assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 14, &marker_selection) == 0); + assert(marker_selection == 0x80); + + assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 14, &marker_selection) == 0); + assert(marker_selection == 0x80); +} + +TEST_SUITE(ble_ll_cs_drbg_test_suite) { + ble_ll_cs_drbg_e_test(); + ble_ll_cs_drbg_f7_test(); + ble_ll_cs_drbg_f8_test(); + ble_ll_cs_drbg_f9_test(); + ble_ll_cs_drbg_rand_test(); + ble_ll_cs_drbg_chan_selection_3b_test(); + ble_ll_cs_drbg_generate_aa_test(); + ble_ll_cs_drbg_rand_marker_position_test(); + ble_ll_cs_drbg_rand_marker_selection_test(); +} diff --git a/nimble/controller/test/src/ble_ll_test.c b/nimble/controller/test/src/ble_ll_test.c index 2b36cb1f3c..c90e9f0d48 100644 --- a/nimble/controller/test/src/ble_ll_test.c +++ b/nimble/controller/test/src/ble_ll_test.c @@ -25,6 +25,7 @@ TEST_SUITE_DECL(ble_ll_aa_test_suite); TEST_SUITE_DECL(ble_ll_crypto_test_suite); TEST_SUITE_DECL(ble_ll_csa2_test_suite); +TEST_SUITE_DECL(ble_ll_cs_drbg_test_suite); int main(int argc, char **argv) @@ -32,6 +33,7 @@ main(int argc, char **argv) ble_ll_aa_test_suite(); ble_ll_crypto_test_suite(); ble_ll_csa2_test_suite(); + ble_ll_cs_drbg_test_suite(); return tu_any_failed; } diff --git a/nimble/controller/test/syscfg.yml b/nimble/controller/test/syscfg.yml index 6edad438bb..30d1a1bef9 100644 --- a/nimble/controller/test/syscfg.yml +++ b/nimble/controller/test/syscfg.yml @@ -23,3 +23,7 @@ syscfg.vals: MCU_TIMER_POLLER_PRIO: 1 MCU_UART_POLLER_PRIO: 2 NATIVE_SOCKETS_PRIO: 3 + MBEDTLS_AES_C: 1 + BLE_VERSION: 54 + BLE_CHANNEL_SOUNDING: 1 + BLE_LL_CHANNEL_SOUNDING: 1 diff --git a/nimble/host/src/ble_cs.c b/nimble/host/src/ble_cs.c index cef622206b..2ae985e225 100644 --- a/nimble/host/src/ble_cs.c +++ b/nimble/host/src/ble_cs.c @@ -689,7 +689,6 @@ ble_hs_hci_evt_le_cs_test_end_complete(uint8_t subevent, const void *data, int ble_cs_initiator_procedure_start(const struct ble_cs_initiator_procedure_start_params *params) { - struct ble_hci_le_cs_rd_loc_supp_cap_rp rsp; struct ble_cs_rd_rem_supp_cap_cp cmd; int rc; @@ -701,6 +700,12 @@ ble_cs_initiator_procedure_start(const struct ble_cs_initiator_procedure_start_p * 5. Start the CS Security Start procedure */ + (void) ble_cs_set_chan_class; + (void) ble_cs_remove_config; + (void) ble_cs_wr_cached_rem_fae; + (void) ble_cs_wr_cached_rem_supp_cap; + (void) ble_cs_rd_loc_supp_cap; + cs_state.cb = params->cb; cs_state.cb_arg = params->cb_arg;