mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
Merge branch 'develop'
HFP/HSP: - store received audio as wav file SM: - send/receive keypress notifications. -> link into docs - derive BR/EDR Link Key from LE LTK established via LE Secure Connection - fix use of stored LTKs in all combinations (LE Legacy Paring/LE Secure Connections - Initiator/Responder) - truncate LTK in LE Secure Connections if established key size is less than 16 bytes - implement slower elliptic curve multiplication -> less than 800 bytes for 32-bit CPUs POSIX: - add le_device_db_fs that stores db at /tmp/btstack_le_device_db.txt as basic csv
This commit is contained in:
commit
140b81662c
3
3rd-party/mbedtls/include/mbedtls/config.h
vendored
3
3rd-party/mbedtls/include/mbedtls/config.h
vendored
@ -2456,7 +2456,8 @@ void sm_mbedtls_allocator_free(void * data);
|
||||
|
||||
/* ECP options */
|
||||
//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */
|
||||
#define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */
|
||||
#define MBEDTLS_ECP_WINDOW_SIZE 1 /**< Maximum window size used - 1 == uses double and add to save RAM */
|
||||
#define MBEDTLS_ECP_MUL_NAIVE_SAFE 0 /**< Enable use of temporary point for window size == 1 - adds ~100 bytes but makes branches independ from n */
|
||||
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */
|
||||
|
||||
/* Entropy options */
|
||||
|
99
3rd-party/mbedtls/library/ecp.c
vendored
99
3rd-party/mbedtls/library/ecp.c
vendored
@ -728,6 +728,25 @@ cleanup:
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) )
|
||||
|
||||
#if defined(ECP_SHORTWEIERSTRASS)
|
||||
|
||||
/*
|
||||
* Check and define parameters used by the comb method (see below for details)
|
||||
*/
|
||||
#if MBEDTLS_ECP_WINDOW_SIZE > 7
|
||||
#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds"
|
||||
#endif
|
||||
|
||||
#if MBEDTLS_ECP_WINDOW_SIZE >= 2
|
||||
#define ECP_COMB_METHOD
|
||||
|
||||
/* d = ceil( n / w ) */
|
||||
#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2
|
||||
|
||||
/* number of precomputed points */
|
||||
#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For curves in short Weierstrass form, we do all the internal operations in
|
||||
* Jacobian coordinates.
|
||||
@ -775,6 +794,7 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#ifdef ECP_COMB_METHOD
|
||||
/*
|
||||
* Normalize jacobian coordinates of an array of (pointers to) points,
|
||||
* using Montgomery's trick to perform only one inversion mod P.
|
||||
@ -887,6 +907,7 @@ cleanup:
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Point doubling R = 2 P, Jacobian coordinates
|
||||
@ -1068,6 +1089,8 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#ifdef ECP_COMB_METHOD
|
||||
|
||||
/*
|
||||
* Randomize jacobian coordinates:
|
||||
* (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l
|
||||
@ -1115,19 +1138,6 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Check and define parameters used by the comb method (see below for details)
|
||||
*/
|
||||
#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7
|
||||
#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds"
|
||||
#endif
|
||||
|
||||
/* d = ceil( n / w ) */
|
||||
#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2
|
||||
|
||||
/* number of precomputed points */
|
||||
#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) )
|
||||
|
||||
/*
|
||||
* Compute the representation of m that will be used with our comb method.
|
||||
*
|
||||
@ -1422,6 +1432,63 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#else /* ECP_COMB_METHOD */
|
||||
|
||||
/*
|
||||
* Multiplication using the double and add method,
|
||||
* for curves in short Weierstrass form to optimize for RAM usage vs. speed
|
||||
*
|
||||
* Implemented by BlueKitchen GmbH
|
||||
* Note:
|
||||
*/
|
||||
static int ecp_mul_naive( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
|
||||
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng )
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
#if MBEDTLS_ECP_MUL_NAIVE_SAFE == 1
|
||||
mbedtls_ecp_point T;
|
||||
mbedtls_ecp_point_init(&T);
|
||||
#endif
|
||||
|
||||
// calculate m * p using double and add in decreasing fashion to use ecp_add_mixed
|
||||
mbedtls_ecp_point_init(R);
|
||||
for (i=grp->nbits;i >= 0;i--){
|
||||
MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) );
|
||||
|
||||
#if MBEDTLS_ECP_MUL_NAIVE_SAFE == 1
|
||||
MBEDTLS_MPI_CHK( ecp_add_mixed(grp, &T, R, P) );
|
||||
int bit_set = mbedtls_mpi_get_bit(m, i);
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign(&R->X, &T.X, bit_set));
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign(&R->Y, &T.Y, bit_set));
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign(&R->Y, &T.Y, bit_set));
|
||||
#else
|
||||
if (mbedtls_mpi_get_bit(m, i)){
|
||||
MBEDTLS_MPI_CHK( ecp_add_mixed(grp, R, R, P) );
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// normalize jacobian coordinates
|
||||
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
|
||||
|
||||
cleanup:
|
||||
|
||||
#if MBEDTLS_ECP_MUL_NAIVE_SAFE == 1
|
||||
mbedtls_ecp_point_free(&T);
|
||||
#endif
|
||||
|
||||
if( ret != 0 )
|
||||
mbedtls_ecp_point_free( R );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#endif /* ECP_COMB_METHOD */
|
||||
|
||||
#endif /* ECP_SHORTWEIERSTRASS */
|
||||
|
||||
#if defined(ECP_MONTGOMERY)
|
||||
@ -1612,8 +1679,8 @@ int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
|
||||
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
|
||||
{
|
||||
int ret;
|
||||
|
||||
int ret;
|
||||
/* Common sanity checks */
|
||||
if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 )
|
||||
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
|
||||
@ -1628,7 +1695,11 @@ int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
|
||||
#endif
|
||||
#if defined(ECP_SHORTWEIERSTRASS)
|
||||
if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
|
||||
#ifdef ECP_COMB_METHOD
|
||||
return( ecp_mul_comb( grp, R, m, P, f_rng, p_rng ) );
|
||||
#else
|
||||
return( ecp_mul_naive( grp, R, m, P, f_rng, p_rng ) );
|
||||
#endif
|
||||
#endif
|
||||
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
|
||||
}
|
||||
|
@ -873,6 +873,15 @@ called.
|
||||
|
||||
After the bonding process, *SM_EVENT_JUST_WORKS_CANCEL*, *SM_EVENT_PASSKEY_DISPLAY_CANCEL*, or *SM_EVENT_NUMERIC_COMPARISON_CANCEL* is emitted to update the user interface if an Just Works request or a passkey has been shown before.
|
||||
|
||||
### Keypress Notifications
|
||||
|
||||
As part of Bluetooth Core V4.2 specification, a device with a keyboard but no display can send keypress notifications to provide better user feedback. In BTstack, the *sm_keypress_notification()* function is used for sending notifcations. Notifications are received by BTstack via the *SM_EVENT_KEYPRESS_NOTIFICATION* event.
|
||||
|
||||
### Cross-transport Key Derivation for LE Secure Connections
|
||||
|
||||
In a dual-mode configuration, BTstack automatically generates an BR/EDR Link Key from the LE LTK via the Link Key Conversion function *h6*. It is then stored in the link key db.
|
||||
|
||||
To derive an LE LTK from a BR/EDR link key, the Bluetooth controller needs to support Secure Connections via NIST P-256 elliptic curves and the LE Secure Connections needs to get established via the LE Transport. BTstack does not support LE Secure Connections via LE Transport currently.
|
||||
|
||||
### Out-of-Band Data with LE Legacy Pairing
|
||||
|
||||
|
@ -48,7 +48,6 @@ GATT_CLIENT += \
|
||||
|
||||
SM_REAL += \
|
||||
sm.c \
|
||||
le_device_db_memory.c \
|
||||
|
||||
PAN += \
|
||||
pan.c \
|
||||
|
@ -450,11 +450,91 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
|
||||
|
||||
if (event[0] == HCI_EVENT_SCO_CAN_SEND_NOW){
|
||||
sco_demo_send(sco_handle);
|
||||
return;
|
||||
switch (packet_type){
|
||||
|
||||
case HCI_SCO_DATA_PACKET:
|
||||
sco_demo_receive(event, event_size);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_PACKET:
|
||||
switch (event[0]){
|
||||
|
||||
case HCI_EVENT_SCO_CAN_SEND_NOW:
|
||||
sco_demo_send(sco_handle);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_HFP_META:
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
handle = hfp_subevent_service_level_connection_established_get_con_handle(event);
|
||||
printf("Service level connection established.\n\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("Service level connection released.\n\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
|
||||
if (hfp_subevent_audio_connection_established_get_status(event)){
|
||||
sco_handle = 0;
|
||||
printf("Audio connection establishment failed with status %u\n", hfp_subevent_audio_connection_established_get_status(event));
|
||||
} else {
|
||||
sco_handle = hfp_subevent_audio_connection_established_get_handle(event);
|
||||
printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
|
||||
hci_request_sco_can_send_now_event();
|
||||
}
|
||||
break;
|
||||
case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
|
||||
sco_handle = 0;
|
||||
printf("Audio connection released\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_COMPLETE:
|
||||
switch (cmd){
|
||||
case 'd':
|
||||
printf("HFP AG registration status update enabled.\n");
|
||||
break;
|
||||
case 'e':
|
||||
printf("HFP AG registration status update for individual indicators set.\n");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED:
|
||||
printf("AG_INDICATOR_STATUS_CHANGED, AG indicator '%s' (index: %d) to: %d\n", (const char*) &event[5], event[3], event[4]);
|
||||
break;
|
||||
case HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED:
|
||||
printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[3], event[4], (char *) &event[5]);
|
||||
break;
|
||||
case HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR:
|
||||
if (event[4])
|
||||
printf("EXTENDED_AUDIO_GATEWAY_ERROR_REPORT, status : %d\n", event[3]);
|
||||
break;
|
||||
case HFP_SUBEVENT_RING:
|
||||
printf("** Ring **\n");
|
||||
break;
|
||||
case HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG:
|
||||
printf("Phone number for voice tag: %s\n", (const char *) &event[3]);
|
||||
break;
|
||||
case HFP_SUBEVENT_SPEAKER_VOLUME:
|
||||
printf("Speaker volume: %u\n", event[3]);
|
||||
break;
|
||||
case HFP_SUBEVENT_MICROPHONE_VOLUME:
|
||||
printf("Microphone volume: %u\n", event[3]);
|
||||
break;
|
||||
default:
|
||||
printf("event not handled %u\n", event[2]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
|
||||
switch (event[2]) {
|
||||
|
@ -47,23 +47,28 @@
|
||||
#define SCO_DEMO_MODE_ASCII 1
|
||||
#define SCO_DEMO_MODE_COUNTER 2
|
||||
|
||||
|
||||
// SCO demo configuration
|
||||
#define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
|
||||
#define SCO_DEMO_MODE SCO_DEMO_MODE_ASCII
|
||||
#define SCO_REPORT_PERIOD 100
|
||||
|
||||
// portaudio config
|
||||
#define NUM_CHANNELS 1
|
||||
#define SAMPLE_RATE 8000
|
||||
#define FRAMES_PER_BUFFER 24
|
||||
#define PA_SAMPLE_TYPE paInt8
|
||||
#ifdef HAVE_POSIX_FILE_IO
|
||||
#define SCO_WAV_FILENAME "sco_input.wav"
|
||||
#define SCO_WAV_DURATION_IN_SECONDS 30
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
|
||||
#define USE_PORTAUDIO
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_PORTAUDIO
|
||||
#include <portaudio.h>
|
||||
// portaudio config
|
||||
#define NUM_CHANNELS 1
|
||||
#define SAMPLE_RATE 8000
|
||||
#define FRAMES_PER_BUFFER 24
|
||||
#define PA_SAMPLE_TYPE paInt8
|
||||
// portaudio globals
|
||||
static PaStream * stream;
|
||||
#endif
|
||||
@ -80,6 +85,71 @@ static const uint8_t sine[] = {
|
||||
#endif
|
||||
|
||||
static int phase;
|
||||
static int count_sent = 0;
|
||||
static int count_received = 0;
|
||||
|
||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||
#ifdef SCO_WAV_FILENAME
|
||||
|
||||
static FILE * wav_file;
|
||||
static int num_samples_to_write;
|
||||
|
||||
|
||||
static void little_endian_fstore_16(FILE * file, uint16_t value){
|
||||
uint8_t buf[2];
|
||||
little_endian_store_32(buf, 0, value);
|
||||
fwrite(&buf, 1, 2, file);
|
||||
}
|
||||
|
||||
static void little_endian_fstore_32(FILE * file, uint32_t value){
|
||||
uint8_t buf[4];
|
||||
little_endian_store_32(buf, 0, value);
|
||||
fwrite(&buf, 1, 4, file);
|
||||
}
|
||||
|
||||
static FILE * wav_init(const char * filename){
|
||||
printf("SCO Demo: creating wav file %s\n", filename);
|
||||
return fopen(filename, "wb");
|
||||
}
|
||||
|
||||
static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){
|
||||
printf("SCO Demo: writing wav header: sample rate %u, num channels %u, duration %u s, bytes per sample %u\n",
|
||||
sample_rate, num_channels, num_samples / sample_rate / num_channels, bytes_per_sample);
|
||||
|
||||
/* write RIFF header */
|
||||
fwrite("RIFF", 1, 4, file);
|
||||
// num_samples = blocks * subbands
|
||||
uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels);
|
||||
little_endian_fstore_32(file, data_bytes + 36);
|
||||
fwrite("WAVE", 1, 4, file);
|
||||
|
||||
int byte_rate = sample_rate * num_channels * bytes_per_sample;
|
||||
int bits_per_sample = 8 * bytes_per_sample;
|
||||
int block_align = num_channels * bits_per_sample;
|
||||
int fmt_length = 16;
|
||||
int fmt_format_tag = 1; // PCM
|
||||
|
||||
/* write fmt chunk */
|
||||
fwrite("fmt ", 1, 4, file);
|
||||
little_endian_fstore_32(file, fmt_length);
|
||||
little_endian_fstore_16(file, fmt_format_tag);
|
||||
little_endian_fstore_16(file, num_channels);
|
||||
little_endian_fstore_32(file, sample_rate);
|
||||
little_endian_fstore_32(file, byte_rate);
|
||||
little_endian_fstore_16(file, block_align);
|
||||
little_endian_fstore_16(file, bits_per_sample);
|
||||
|
||||
/* write data chunk */
|
||||
fwrite("data", 1, 4, file);
|
||||
little_endian_fstore_32(file, data_bytes);
|
||||
}
|
||||
|
||||
static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){
|
||||
fwrite(data, num_samples, 1, file);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void sco_demo_init(void){
|
||||
|
||||
@ -98,6 +168,18 @@ void sco_demo_init(void){
|
||||
printf("SCO Demo: Sending counter value, hexdump received data.\n");
|
||||
#endif
|
||||
|
||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||
#ifdef SCO_WAV_FILENAME
|
||||
wav_file = wav_init(SCO_WAV_FILENAME);
|
||||
const int sample_rate = 8000;
|
||||
const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
|
||||
const int num_channels = 1;
|
||||
const int bytes_per_sample = 1;
|
||||
write_wav_header(wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
|
||||
num_samples_to_write = num_samples;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_PORTAUDIO
|
||||
int err;
|
||||
PaStreamParameters outputParameters;
|
||||
@ -136,6 +218,9 @@ void sco_demo_init(void){
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sco_report(void){
|
||||
printf("SCO: sent %u, received %u\n", count_sent, count_received);
|
||||
}
|
||||
|
||||
void sco_demo_send(hci_con_handle_t sco_handle){
|
||||
|
||||
@ -164,8 +249,9 @@ void sco_demo_send(hci_con_handle_t sco_handle){
|
||||
memset(&sco_packet[3], phase++, frames_per_packet);
|
||||
if (phase > 'z') phase = 'a';
|
||||
#else
|
||||
for (i=0;i<frames_per_packet;i++){
|
||||
sco_packet[3+i] = phase++;
|
||||
int j;
|
||||
for (j=0;j<frames_per_packet;j++){
|
||||
sco_packet[3+j] = phase++;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -174,9 +260,8 @@ void sco_demo_send(hci_con_handle_t sco_handle){
|
||||
// request another send event
|
||||
hci_request_sco_can_send_now_event();
|
||||
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count % SCO_REPORT_PERIOD) == 0) printf("SCO: sent %u\n", count);
|
||||
count_sent++;
|
||||
if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,11 +269,39 @@ void sco_demo_send(hci_con_handle_t sco_handle){
|
||||
*/
|
||||
void sco_demo_receive(uint8_t * packet, uint16_t size){
|
||||
|
||||
if (packet[1] & 0xf0){
|
||||
printf("SCO CRC Error: %x - data: ", packet[1] >> 4);
|
||||
printf_hexdump(&packet[3], size-3);
|
||||
return;
|
||||
}
|
||||
|
||||
int dump_data = 1;
|
||||
|
||||
count_received++;
|
||||
// if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
|
||||
|
||||
|
||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||
#ifdef SCO_WAV_FILENAME
|
||||
if (num_samples_to_write){
|
||||
const int num_samples = size - 3;
|
||||
const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
|
||||
// convert 8 bit signed to 8 bit unsigned
|
||||
int i;
|
||||
for (i=0;i<samples_to_write;i++){
|
||||
packet[3+i] += 128;
|
||||
}
|
||||
write_wav_data_uint8(wav_file, samples_to_write, &packet[3]);
|
||||
num_samples_to_write -= samples_to_write;
|
||||
if (num_samples_to_write == 0){
|
||||
printf("SCO Demo: closing wav file\n");
|
||||
fclose(wav_file);
|
||||
}
|
||||
dump_data = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (packet[1] & 0xf0){
|
||||
printf("SCO CRC Error: %x - data: ", packet[1] >> 4);
|
||||
printf_hexdump(&packet[3], size-3);
|
||||
return;
|
||||
}
|
||||
|
||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||
#ifdef USE_PORTAUDIO
|
||||
@ -198,22 +311,21 @@ void sco_demo_receive(uint8_t * packet, uint16_t size){
|
||||
if (end - start > 5){
|
||||
printf("Portaudio: write stream took %u ms\n", end - start);
|
||||
}
|
||||
#else
|
||||
printf_hexdump(&packet[3], size-3);
|
||||
dump_data = 0;
|
||||
#endif
|
||||
#else
|
||||
printf("data: ");
|
||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
|
||||
int i;
|
||||
for (i=3;i<size;i++){
|
||||
printf("%c", packet[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
printf_hexdump(&packet[3], size-3);
|
||||
#endif
|
||||
|
||||
static int count = 0;
|
||||
count++;
|
||||
if ((count % SCO_REPORT_PERIOD) == 0) printf("SCO: received %u\n", count);
|
||||
if (dump_data){
|
||||
printf("data: ");
|
||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
|
||||
int i;
|
||||
for (i=3;i<size;i++){
|
||||
printf("%c", packet[i]);
|
||||
}
|
||||
printf("\n");
|
||||
dump_data = 0;
|
||||
#else
|
||||
printf_hexdump(&packet[3], size-3);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
382
platform/posix/le_device_db_fs.c
Normal file
382
platform/posix/le_device_db_fs.c
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (C) 2014 BlueKitchen GmbH
|
||||
*
|
||||
* 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 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 the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD 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.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ble/le_device_db.h"
|
||||
|
||||
#include "ble/core.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "btstack_debug.h"
|
||||
|
||||
// Central Device db implemenation using static memory
|
||||
typedef struct le_device_memory_db {
|
||||
|
||||
// Identification
|
||||
int addr_type;
|
||||
bd_addr_t addr;
|
||||
sm_key_t irk;
|
||||
|
||||
// Stored pairing information allows to re-establish an enncrypted connection
|
||||
// with a peripheral that doesn't have any persistent memory
|
||||
sm_key_t ltk;
|
||||
uint16_t ediv;
|
||||
uint8_t rand[8];
|
||||
uint8_t key_size;
|
||||
uint8_t authenticated;
|
||||
uint8_t authorized;
|
||||
|
||||
// Signed Writes by remote
|
||||
sm_key_t remote_csrk;
|
||||
uint32_t remote_counter;
|
||||
|
||||
// Signed Writes by us
|
||||
sm_key_t local_csrk;
|
||||
uint32_t local_counter;
|
||||
|
||||
} le_device_memory_db_t;
|
||||
|
||||
#define LE_DEVICE_MEMORY_SIZE 20
|
||||
#define INVALID_ENTRY_ADDR_TYPE 0xff
|
||||
#define DB_PATH_TEMPLATE "/tmp/btstack_at_%s_le_device_db.txt"
|
||||
const char * csv_header = "# addr_type, addr, irk, ltk, ediv, rand[8], key_size, authenticated, authorized, remote_csrk, remote_counter, local_csrk, local_counter";
|
||||
static char db_path[sizeof(DB_PATH_TEMPLATE) - 2 + 17 + 1];
|
||||
|
||||
static le_device_memory_db_t le_devices[LE_DEVICE_MEMORY_SIZE];
|
||||
|
||||
static char bd_addr_to_dash_str_buffer[6*3]; // 12-45-78-01-34-67\0
|
||||
static char * bd_addr_to_dash_str(bd_addr_t addr){
|
||||
char * p = bd_addr_to_dash_str_buffer;
|
||||
int i;
|
||||
for (i = 0; i < 6 ; i++) {
|
||||
*p++ = char_for_nibble((addr[i] >> 4) & 0x0F);
|
||||
*p++ = char_for_nibble((addr[i] >> 0) & 0x0F);
|
||||
*p++ = '-';
|
||||
}
|
||||
*--p = 0;
|
||||
return (char *) bd_addr_to_dash_str_buffer;
|
||||
}
|
||||
|
||||
static inline void write_delimiter(FILE * wFile){
|
||||
fwrite(", ", 1, 1, wFile);
|
||||
}
|
||||
static inline void write_hex_byte(FILE * wFile, uint8_t value){
|
||||
char buffer[2];
|
||||
buffer[0] = char_for_nibble(value >> 4);
|
||||
buffer[1] = char_for_nibble(value & 0x0f);
|
||||
fwrite(buffer, 2, 1, wFile);
|
||||
}
|
||||
|
||||
static inline void write_str(FILE * wFile, const char * str){
|
||||
fwrite(str, strlen(str), 1, wFile);
|
||||
write_delimiter(wFile);
|
||||
}
|
||||
static void write_hex(FILE * wFile, const uint8_t * value, int len){
|
||||
int i;
|
||||
for (i = 0; i < len; i++){
|
||||
write_hex_byte(wFile, value[i]);
|
||||
}
|
||||
write_delimiter(wFile);
|
||||
}
|
||||
static void write_value(FILE * wFile, uint32_t value, int len){
|
||||
switch (len){
|
||||
case 4:
|
||||
write_hex_byte(wFile, value >> 24);
|
||||
case 3:
|
||||
write_hex_byte(wFile, value >> 16);
|
||||
case 2:
|
||||
write_hex_byte(wFile, value >> 8);
|
||||
case 1:
|
||||
default:
|
||||
write_hex_byte(wFile, value);
|
||||
}
|
||||
write_delimiter(wFile);
|
||||
}
|
||||
|
||||
static void le_device_db_store(void) {
|
||||
int i;
|
||||
// open file
|
||||
FILE * wFile = fopen(db_path,"w+");
|
||||
if (wFile == NULL) return;
|
||||
fwrite(csv_header, strlen(csv_header), 1, wFile);
|
||||
fwrite("\n", 1, 1, wFile);
|
||||
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
|
||||
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE) continue;
|
||||
write_value(wFile, le_devices[i].addr_type, 1);
|
||||
write_str(wFile, bd_addr_to_str(le_devices[i].addr));
|
||||
write_hex(wFile, le_devices[i].irk, 16);
|
||||
write_hex(wFile, le_devices[i].ltk, 16);
|
||||
write_value(wFile, le_devices[i].ediv, 2);
|
||||
write_hex(wFile, le_devices[i].rand, 8);
|
||||
write_value(wFile, le_devices[i].key_size, 1);
|
||||
write_value(wFile, le_devices[i].authenticated, 1);
|
||||
write_value(wFile, le_devices[i].authorized, 1);
|
||||
write_hex(wFile, le_devices[i].remote_csrk, 16);
|
||||
write_value(wFile, le_devices[i].remote_counter, 2);
|
||||
write_hex(wFile, le_devices[i].local_csrk, 16);
|
||||
write_value(wFile, le_devices[i].local_counter, 2);
|
||||
fwrite("\n", 1, 1, wFile);
|
||||
}
|
||||
fclose(wFile);
|
||||
}
|
||||
static void read_delimiter(FILE * wFile){
|
||||
fgetc(wFile);
|
||||
}
|
||||
|
||||
static uint8_t read_hex_byte(FILE * wFile){
|
||||
int c = fgetc(wFile);
|
||||
if (c == ':') {
|
||||
c = fgetc(wFile);
|
||||
}
|
||||
int d = fgetc(wFile);
|
||||
return nibble_for_char(c) << 4 | nibble_for_char(d);
|
||||
}
|
||||
|
||||
static void read_hex(FILE * wFile, uint8_t * buffer, int len){
|
||||
int i;
|
||||
for (i=0;i<len;i++){
|
||||
buffer[i] = read_hex_byte(wFile);
|
||||
}
|
||||
read_delimiter(wFile);
|
||||
}
|
||||
|
||||
static uint32_t read_value(FILE * wFile, int len){
|
||||
uint32_t res = 0;
|
||||
int i;
|
||||
for (i=0;i<len;i++){
|
||||
res = res << 8 | read_hex_byte(wFile);
|
||||
}
|
||||
read_delimiter(wFile);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void le_device_db_read(void){
|
||||
// open file
|
||||
FILE * wFile = fopen(db_path,"r");
|
||||
if (wFile == NULL) return;
|
||||
// skip header
|
||||
while (1) {
|
||||
int c = fgetc(wFile);
|
||||
if (feof(wFile)) goto exit;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
// read entries
|
||||
int i;
|
||||
for (i=0;i<LE_DEVICE_MEMORY_SIZE && !feof(wFile);i++){
|
||||
le_devices[i].addr_type = read_value(wFile, 1);
|
||||
read_hex(wFile, le_devices[i].addr, 6);
|
||||
read_hex(wFile, le_devices[i].irk, 16);
|
||||
read_hex(wFile, le_devices[i].ltk, 16);
|
||||
le_devices[i].ediv = read_value(wFile, 2);
|
||||
read_hex(wFile, le_devices[i].rand, 8);
|
||||
le_devices[i].key_size = read_value(wFile, 1);
|
||||
le_devices[i].authenticated = read_value(wFile, 1);
|
||||
le_devices[i].authorized = read_value(wFile, 1);
|
||||
read_hex(wFile, le_devices[i].remote_csrk, 16);
|
||||
le_devices[i].remote_counter = read_value(wFile, 2);
|
||||
read_hex(wFile, le_devices[i].local_csrk, 16);
|
||||
le_devices[i].local_counter = read_value(wFile, 2);
|
||||
// read newling
|
||||
fgetc(wFile);
|
||||
}
|
||||
exit:
|
||||
fclose(wFile);
|
||||
}
|
||||
|
||||
void le_device_db_init(void){
|
||||
int i;
|
||||
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
|
||||
le_devices[i].addr_type = INVALID_ENTRY_ADDR_TYPE;
|
||||
}
|
||||
sprintf(db_path, DB_PATH_TEMPLATE, "00-00-00-00-00-00");
|
||||
}
|
||||
|
||||
void le_device_db_set_local_bd_addr(bd_addr_t addr){
|
||||
sprintf(db_path, DB_PATH_TEMPLATE, bd_addr_to_dash_str(addr));
|
||||
log_info("le_device_db_fs: path %s", db_path);
|
||||
le_device_db_read();
|
||||
le_device_db_dump();
|
||||
}
|
||||
|
||||
// @returns number of device in db
|
||||
int le_device_db_count(void){
|
||||
int i;
|
||||
int counter = 0;
|
||||
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
|
||||
if (le_devices[i].addr_type != INVALID_ENTRY_ADDR_TYPE) counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
// free device
|
||||
void le_device_db_remove(int index){
|
||||
le_devices[index].addr_type = INVALID_ENTRY_ADDR_TYPE;
|
||||
le_device_db_store();
|
||||
}
|
||||
|
||||
int le_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk){
|
||||
int i;
|
||||
int index = -1;
|
||||
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
|
||||
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE){
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) return -1;
|
||||
|
||||
log_info("Central Device DB adding type %u - %s", addr_type, bd_addr_to_str(addr));
|
||||
log_info_key("irk", irk);
|
||||
|
||||
le_devices[index].addr_type = addr_type;
|
||||
memcpy(le_devices[index].addr, addr, 6);
|
||||
memcpy(le_devices[index].irk, irk, 16);
|
||||
le_devices[index].remote_counter = 0;
|
||||
|
||||
le_device_db_store();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
// get device information: addr type and address
|
||||
void le_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t irk){
|
||||
if (addr_type) *addr_type = le_devices[index].addr_type;
|
||||
if (addr) memcpy(addr, le_devices[index].addr, 6);
|
||||
if (irk) memcpy(irk, le_devices[index].irk, 16);
|
||||
}
|
||||
|
||||
void le_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk, int key_size, int authenticated, int authorized){
|
||||
log_info("Central Device DB set encryption for %u, ediv x%04x, key size %u, authenticated %u, authorized %u",
|
||||
index, ediv, key_size, authenticated, authorized);
|
||||
le_device_memory_db_t * device = &le_devices[index];
|
||||
device->ediv = ediv;
|
||||
if (rand) memcpy(device->rand, rand, 8);
|
||||
if (ltk) memcpy(device->ltk, ltk, 16);
|
||||
device->key_size = key_size;
|
||||
device->authenticated = authenticated;
|
||||
device->authorized = authorized;
|
||||
|
||||
le_device_db_store();
|
||||
}
|
||||
|
||||
void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk, int * key_size, int * authenticated, int * authorized){
|
||||
le_device_memory_db_t * device = &le_devices[index];
|
||||
log_info("Central Device DB encryption for %u, ediv x%04x, keysize %u, authenticated %u, authorized %u",
|
||||
index, device->ediv, device->key_size, device->authenticated, device->authorized);
|
||||
if (ediv) *ediv = device->ediv;
|
||||
if (rand) memcpy(rand, device->rand, 8);
|
||||
if (ltk) memcpy(ltk, device->ltk, 16);
|
||||
if (key_size) *key_size = device->key_size;
|
||||
if (authenticated) *authenticated = device->authenticated;
|
||||
if (authorized) *authorized = device->authorized;
|
||||
}
|
||||
|
||||
// get signature key
|
||||
void le_device_db_remote_csrk_get(int index, sm_key_t csrk){
|
||||
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
|
||||
log_error("le_device_db_remote_csrk_get called with invalid index %d", index);
|
||||
return;
|
||||
}
|
||||
if (csrk) memcpy(csrk, le_devices[index].remote_csrk, 16);
|
||||
}
|
||||
|
||||
void le_device_db_remote_csrk_set(int index, sm_key_t csrk){
|
||||
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
|
||||
log_error("le_device_db_remote_csrk_set called with invalid index %d", index);
|
||||
return;
|
||||
}
|
||||
if (csrk) memcpy(le_devices[index].remote_csrk, csrk, 16);
|
||||
|
||||
le_device_db_store();
|
||||
}
|
||||
|
||||
void le_device_db_local_csrk_get(int index, sm_key_t csrk){
|
||||
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
|
||||
log_error("le_device_db_local_csrk_get called with invalid index %d", index);
|
||||
return;
|
||||
}
|
||||
if (csrk) memcpy(csrk, le_devices[index].local_csrk, 16);
|
||||
}
|
||||
|
||||
void le_device_db_local_csrk_set(int index, sm_key_t csrk){
|
||||
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
|
||||
log_error("le_device_db_local_csrk_set called with invalid index %d", index);
|
||||
return;
|
||||
}
|
||||
if (csrk) memcpy(le_devices[index].local_csrk, csrk, 16);
|
||||
|
||||
le_device_db_store();
|
||||
}
|
||||
|
||||
// query last used/seen signing counter
|
||||
uint32_t le_device_db_remote_counter_get(int index){
|
||||
return le_devices[index].remote_counter;
|
||||
}
|
||||
|
||||
// update signing counter
|
||||
void le_device_db_remote_counter_set(int index, uint32_t counter){
|
||||
le_devices[index].remote_counter = counter;
|
||||
|
||||
le_device_db_store();
|
||||
}
|
||||
|
||||
// query last used/seen signing counter
|
||||
uint32_t le_device_db_local_counter_get(int index){
|
||||
return le_devices[index].local_counter;
|
||||
}
|
||||
|
||||
// update signing counter
|
||||
void le_device_db_local_counter_set(int index, uint32_t counter){
|
||||
le_devices[index].local_counter = counter;
|
||||
|
||||
le_device_db_store();
|
||||
}
|
||||
|
||||
void le_device_db_dump(void){
|
||||
log_info("Central Device DB dump, devices: %d", le_device_db_count());
|
||||
int i;
|
||||
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
|
||||
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE) continue;
|
||||
log_info("%u: %u %s", i, le_devices[i].addr_type, bd_addr_to_str(le_devices[i].addr));
|
||||
log_info_key("ltk", le_devices[i].ltk);
|
||||
log_info_key("irk", le_devices[i].irk);
|
||||
log_info_key("local csrk", le_devices[i].local_csrk);
|
||||
log_info_key("remote csrk", le_devices[i].remote_csrk);
|
||||
}
|
||||
}
|
58
platform/posix/le_device_db_fs.h
Normal file
58
platform/posix/le_device_db_fs.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2016 BlueKitchen GmbH
|
||||
*
|
||||
* 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 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 the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD 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.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LE_DEVICE_DB_FS_H
|
||||
#define __LE_DEVICE_DB_FS_H
|
||||
|
||||
#include "ble/le_device_db.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @brief Get le device db implementation that stores bonding information in /tmp
|
||||
*/
|
||||
const le_device_db_t * le_device_db_fs_instance(void);
|
||||
|
||||
/* API_END */
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __LE_DEVICE_DB_FS_H
|
17
port/libusb/.gitignore
vendored
17
port/libusb/.gitignore
vendored
@ -8,14 +8,20 @@ gap_dedicated_bonding
|
||||
gap_inquiry
|
||||
gap_inquiry_and_bond
|
||||
gap_le_advertisements
|
||||
gap_le_advertisements
|
||||
gatt_battery_query
|
||||
gatt_browser
|
||||
hfp_ag_demo
|
||||
hfp_hf_demo
|
||||
hsp_ag_demo
|
||||
hsp_hs_demo
|
||||
l2cap_test
|
||||
le_counter
|
||||
le_counter.h
|
||||
le_streamer
|
||||
le_streamer
|
||||
le_streamer
|
||||
le_streamer.h
|
||||
le_streamer.h
|
||||
led_counter
|
||||
panu_demo
|
||||
@ -23,14 +29,11 @@ profile.h
|
||||
sdp_bnep_query
|
||||
sdp_general_query
|
||||
sdp_rfcomm_query
|
||||
sm_pairing_central
|
||||
sm_pairing_peripheral
|
||||
sm_pairing_peripheral.h
|
||||
spp_and_le_counter
|
||||
spp_and_le_counter.h
|
||||
spp_counter
|
||||
spp_streamer
|
||||
le_streamer
|
||||
le_streamer.h
|
||||
gap_le_advertisements
|
||||
le_streamer
|
||||
spp_streamer
|
||||
hfp_ag_demo
|
||||
hfp_hf_demo
|
||||
spp_streamer
|
@ -3,7 +3,7 @@ BTSTACK_ROOT = ../..
|
||||
|
||||
CORE += main.c stdin_support.c
|
||||
|
||||
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c
|
||||
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c le_device_db_fs.c
|
||||
|
||||
include ${BTSTACK_ROOT}/example/Makefile.inc
|
||||
|
||||
|
27
port/posix-h4/.gitignore
vendored
27
port/posix-h4/.gitignore
vendored
@ -3,28 +3,41 @@ ancs_client_demo.h
|
||||
ble_central_test
|
||||
ble_peripheral
|
||||
ble_peripheral_sm_minimal
|
||||
ble_peripheral_test
|
||||
bluetooth_init_cc2560_2.44.c
|
||||
bluetooth_init_cc2560a_2.14.c
|
||||
bluetooth_init_cc2560B_1.2_BT_Spec_4.0.c
|
||||
bluetooth_init_cc2564_2.14.c
|
||||
bluetooth_init_cc2564B_1.2_BT_Spec_4.0.c
|
||||
bnep_test
|
||||
classic_test
|
||||
gap_dedicated_bonding
|
||||
gap_inquiry
|
||||
gap_inquiry_and_bond
|
||||
gap_le_advertisements
|
||||
gatt_battery_query
|
||||
gatt_browser
|
||||
hfp_ag_demo
|
||||
hfp_hf_demo
|
||||
hsp_ag_demo
|
||||
hsp_ag_test
|
||||
hsp_hs_demo
|
||||
hsp_hs_test
|
||||
l2cap_test
|
||||
le_counter
|
||||
le_counter.h
|
||||
le_streamer
|
||||
le_streamer.h
|
||||
led_counter
|
||||
profile.h
|
||||
sco_input.wav
|
||||
sdp_bnep_query
|
||||
sdp_general_query
|
||||
sdp_rfcomm_query
|
||||
sm_pairing_peripheral.h
|
||||
spp_and_le_counter
|
||||
spp_and_le_counter.h
|
||||
spp_counter
|
||||
spp_streamer
|
||||
led_counter
|
||||
le_counter.h
|
||||
ble_peripheral_test
|
||||
le_counter
|
||||
gap_le_advertisements
|
||||
le_streamer
|
||||
le_streamer.h
|
||||
TIInit_12.10.28.c
|
||||
TIInit_12.8.32.c
|
@ -2,6 +2,7 @@
|
||||
BTSTACK_ROOT = ../..
|
||||
|
||||
CORE += \
|
||||
bluetooth_init_cc2564B_1.4_BT_Spec_4.1.c \
|
||||
btstack_chipset_cc256x.c \
|
||||
btstack_chipset_csr.c \
|
||||
btstack_chipset_em9301.c \
|
||||
@ -11,9 +12,9 @@ CORE += \
|
||||
btstack_run_loop_posix.c \
|
||||
btstack_uart_block_posix.c \
|
||||
hci_transport_h4.c \
|
||||
le_device_db_fs.c \
|
||||
main.c \
|
||||
stdin_support.c \
|
||||
bluetooth_init_cc2564B_1.4_BT_Spec_4.1.c \
|
||||
# bluetooth_init_cc2564_2.14.c \
|
||||
# btstack_chipset_bcm.c \
|
||||
|
||||
|
@ -13,6 +13,7 @@ CORE += \
|
||||
btstack_uart_block_posix.c \
|
||||
btstack_slip.c \
|
||||
hci_transport_h5.c \
|
||||
le_device_db_fs.c \
|
||||
main.c \
|
||||
stdin_support.c \
|
||||
# btstack_chipset_bcm.c \
|
||||
|
@ -326,7 +326,7 @@ static void att_run(void){
|
||||
log_info("Orig Signature: ");
|
||||
log_info_hexdump( &att_request_buffer[att_request_size-8], 8);
|
||||
uint16_t attribute_handle = little_endian_read_16(att_request_buffer, 1);
|
||||
sm_cmac_start(csrk, att_request_buffer[0], attribute_handle, att_request_size - 15, &att_request_buffer[3], counter_packet, att_signed_write_handle_cmac_result);
|
||||
sm_cmac_signed_write_start(csrk, att_request_buffer[0], attribute_handle, att_request_size - 15, &att_request_buffer[3], counter_packet, att_signed_write_handle_cmac_result);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -965,7 +965,7 @@ static void gatt_client_run(void){
|
||||
le_device_db_local_csrk_get(peripheral->le_device_index, csrk);
|
||||
uint32_t sign_counter = le_device_db_local_counter_get(peripheral->le_device_index);
|
||||
peripheral->gatt_client_state = P_W4_CMAC_RESULT;
|
||||
sm_cmac_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
|
||||
sm_cmac_signed_write_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -67,6 +67,13 @@ extern "C" {
|
||||
*/
|
||||
void le_device_db_init(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief sets local bd addr. allows for db per Bluetooth controller
|
||||
* @param bd_addr
|
||||
*/
|
||||
void le_device_db_set_local_bd_addr(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief add device to db
|
||||
* @param addr_type, address of the device
|
||||
|
@ -82,6 +82,9 @@ void le_device_db_init(void){
|
||||
}
|
||||
}
|
||||
|
||||
void le_device_db_set_local_bd_addr(bd_addr_t bd_addr){
|
||||
}
|
||||
|
||||
// @returns number of device in db
|
||||
int le_device_db_count(void){
|
||||
int i;
|
||||
|
341
src/ble/sm.c
341
src/ble/sm.c
@ -231,8 +231,11 @@ static uint8_t ec_qx[32];
|
||||
static uint8_t ec_qy[32];
|
||||
static uint8_t ec_d[32];
|
||||
#ifndef HAVE_MALLOC
|
||||
// 4304 bytes with 73 allocations
|
||||
#define MBEDTLS_ALLOC_BUFFER_SIZE (1300+23*sizeof(void *))
|
||||
// COMP Method with Window 2
|
||||
// 1300 bytes with 23 allocations
|
||||
// #define MBEDTLS_ALLOC_BUFFER_SIZE (1300+23*sizeof(void *))
|
||||
// NAIVE Method with safe cond assignments (without safe cond, order changes and allocations fail)
|
||||
#define MBEDTLS_ALLOC_BUFFER_SIZE (700+18*sizeof(void *))
|
||||
static uint8_t mbedtls_memory_buffer[MBEDTLS_ALLOC_BUFFER_SIZE];
|
||||
#endif
|
||||
#endif
|
||||
@ -254,6 +257,7 @@ typedef struct sm_setup_context {
|
||||
|
||||
// user response, (Phase 1 and/or 2)
|
||||
uint8_t sm_user_response;
|
||||
uint8_t sm_keypress_notification;
|
||||
|
||||
// defines which keys will be send after connection is encrypted - calculated during Phase 1, used Phase 3
|
||||
int sm_key_distribution_send_set;
|
||||
@ -287,7 +291,7 @@ typedef struct sm_setup_context {
|
||||
sm_key_t sm_local_dhkey_check;
|
||||
sm_key_t sm_ra;
|
||||
sm_key_t sm_rb;
|
||||
sm_key_t sm_t; // used for f5
|
||||
sm_key_t sm_t; // used for f5 and h6
|
||||
sm_key_t sm_mackey;
|
||||
uint8_t sm_passkey_bit; // also stores number of generated random bytes for EC key generation
|
||||
#endif
|
||||
@ -328,9 +332,6 @@ static uint16_t sm_active_connection = 0;
|
||||
// stores oob data in provided 16 byte buffer if not null
|
||||
static int (*sm_get_oob_data)(uint8_t addres_type, bd_addr_t addr, uint8_t * oob_data) = NULL;
|
||||
|
||||
// used to notify applicationss that user interaction is neccessary, see sm_notify_t below
|
||||
static btstack_packet_handler_t sm_client_packet_handler = NULL;
|
||||
|
||||
// horizontal: initiator capabilities
|
||||
// vertial: responder capabilities
|
||||
static const stk_generation_method_t stk_generation_method [5] [5] = {
|
||||
@ -650,20 +651,6 @@ static void aes_cmac(sm_key_t aes_cmac, const sm_key_t key, const uint8_t * data
|
||||
aes128_calc_cyphertext(key, sm_cmac_y, aes_cmac);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Link Key Conversion Function h6
|
||||
//
|
||||
// h6(W, keyID) = AES-CMACW(keyID)
|
||||
// - W is 128 bits
|
||||
// - keyID is 32 bits
|
||||
static void h6(sm_key_t res, const sm_key_t w, const uint32_t key_id){
|
||||
uint8_t key_id_buffer[4];
|
||||
big_endian_store_32(key_id_buffer, 0, key_id);
|
||||
aes_cmac(res, w, key_id_buffer, 4);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void sm_setup_event_base(uint8_t * event, int event_size, uint8_t type, hci_con_handle_t con_handle, uint8_t addr_type, bd_addr_t address){
|
||||
@ -675,9 +662,6 @@ static void sm_setup_event_base(uint8_t * event, int event_size, uint8_t type, h
|
||||
}
|
||||
|
||||
static void sm_dispatch_event(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
|
||||
if (sm_client_packet_handler) {
|
||||
sm_client_packet_handler(HCI_EVENT_PACKET, 0, packet, size);
|
||||
}
|
||||
// dispatch to all event handlers
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &sm_event_handlers);
|
||||
@ -872,23 +856,8 @@ static int sm_cmac_last_block_complete(void){
|
||||
return (sm_cmac_message_len & 0x0f) == 0;
|
||||
}
|
||||
|
||||
static inline uint8_t sm_cmac_message_get_byte(uint16_t offset){
|
||||
if (offset >= sm_cmac_message_len) {
|
||||
log_error("sm_cmac_message_get_byte. out of bounds, access %u, len %u", offset, sm_cmac_message_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = sm_cmac_message_len - 1 - offset;
|
||||
|
||||
// sm_cmac_header[3] | message[] | sm_cmac_sign_counter[4]
|
||||
if (offset < 3){
|
||||
return sm_cmac_header[offset];
|
||||
}
|
||||
int actual_message_len_incl_header = sm_cmac_message_len - 4;
|
||||
if (offset < actual_message_len_incl_header){
|
||||
return sm_cmac_message[offset - 3];
|
||||
}
|
||||
return sm_cmac_sign_counter[offset - actual_message_len_incl_header];
|
||||
int sm_cmac_ready(void){
|
||||
return sm_cmac_state == CMAC_IDLE;
|
||||
}
|
||||
|
||||
// generic cmac calculation
|
||||
@ -918,19 +887,35 @@ void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*g
|
||||
}
|
||||
|
||||
// cmac for ATT Message signing
|
||||
void sm_cmac_start(const sm_key_t k, uint8_t opcode, hci_con_handle_t con_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t * hash)){
|
||||
static uint8_t sm_cmac_signed_write_message_get_byte(uint16_t offset){
|
||||
if (offset >= sm_cmac_message_len) {
|
||||
log_error("sm_cmac_signed_write_message_get_byte. out of bounds, access %u, len %u", offset, sm_cmac_message_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = sm_cmac_message_len - 1 - offset;
|
||||
|
||||
// sm_cmac_header[3] | message[] | sm_cmac_sign_counter[4]
|
||||
if (offset < 3){
|
||||
return sm_cmac_header[offset];
|
||||
}
|
||||
int actual_message_len_incl_header = sm_cmac_message_len - 4;
|
||||
if (offset < actual_message_len_incl_header){
|
||||
return sm_cmac_message[offset - 3];
|
||||
}
|
||||
return sm_cmac_sign_counter[offset - actual_message_len_incl_header];
|
||||
}
|
||||
|
||||
void sm_cmac_signed_write_start(const sm_key_t k, uint8_t opcode, hci_con_handle_t con_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t * hash)){
|
||||
// ATT Message Signing
|
||||
sm_cmac_header[0] = opcode;
|
||||
little_endian_store_16(sm_cmac_header, 1, con_handle);
|
||||
little_endian_store_32(sm_cmac_sign_counter, 0, sign_counter);
|
||||
uint16_t total_message_len = 3 + message_len + 4; // incl. virtually prepended att opcode, handle and appended sign_counter in LE
|
||||
sm_cmac_message = message;
|
||||
sm_cmac_general_start(k, total_message_len, &sm_cmac_message_get_byte, done_handler);
|
||||
sm_cmac_general_start(k, total_message_len, &sm_cmac_signed_write_message_get_byte, done_handler);
|
||||
}
|
||||
|
||||
int sm_cmac_ready(void){
|
||||
return sm_cmac_state == CMAC_IDLE;
|
||||
}
|
||||
|
||||
static void sm_cmac_handle_aes_engine_ready(void){
|
||||
switch (sm_cmac_state){
|
||||
@ -1100,11 +1085,16 @@ static int sm_key_distribution_flags_for_auth_req(void){
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void sm_reset_setup(void){
|
||||
// fill in sm setup
|
||||
setup->sm_state_vars = 0;
|
||||
setup->sm_keypress_notification = 0xff;
|
||||
sm_reset_tk();
|
||||
}
|
||||
|
||||
static void sm_init_setup(sm_connection_t * sm_conn){
|
||||
|
||||
// fill in sm setup
|
||||
setup->sm_state_vars = 0;
|
||||
sm_reset_tk();
|
||||
setup->sm_peer_addr_type = sm_conn->sm_peer_addr_type;
|
||||
memcpy(setup->sm_peer_address, sm_conn->sm_peer_address, 6);
|
||||
|
||||
@ -1188,7 +1178,7 @@ static void sm_address_resolution_handle_event(address_resolution_event_t event)
|
||||
hci_con_handle_t con_handle = 0;
|
||||
|
||||
sm_connection_t * sm_connection;
|
||||
uint16_t ediv;
|
||||
sm_key_t ltk;
|
||||
switch (mode){
|
||||
case ADDRESS_RESOLUTION_GENERAL:
|
||||
break;
|
||||
@ -1204,8 +1194,8 @@ static void sm_address_resolution_handle_event(address_resolution_event_t event)
|
||||
if (!sm_connection->sm_bonding_requested && !sm_connection->sm_security_request_received) break;
|
||||
sm_connection->sm_security_request_received = 0;
|
||||
sm_connection->sm_bonding_requested = 0;
|
||||
le_device_db_encryption_get(sm_connection->sm_le_db_index, &ediv, NULL, NULL, NULL, NULL, NULL);
|
||||
if (ediv){
|
||||
le_device_db_encryption_get(sm_connection->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL);
|
||||
if (!sm_is_null_key(ltk)){
|
||||
sm_connection->sm_engine_state = SM_INITIATOR_PH0_HAS_LTK;
|
||||
} else {
|
||||
sm_connection->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
|
||||
@ -1278,7 +1268,6 @@ static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){
|
||||
}
|
||||
|
||||
if (le_db_index >= 0){
|
||||
le_device_db_local_counter_set(le_db_index, 0);
|
||||
|
||||
// store local CSRK
|
||||
if (setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
|
||||
@ -1294,13 +1283,23 @@ static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){
|
||||
le_device_db_remote_counter_set(le_db_index, 0);
|
||||
}
|
||||
|
||||
// store encryption information
|
||||
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION
|
||||
&& setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION){
|
||||
// store encryption information for secure connections: LTK generated by ECDH
|
||||
if (setup->sm_use_secure_connections){
|
||||
log_info("sm: store SC LTK (key size %u, authenticatd %u)", sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated);
|
||||
uint8_t zero_rand[8];
|
||||
memset(zero_rand, 0, 8);
|
||||
le_device_db_encryption_set(le_db_index, 0, zero_rand, setup->sm_ltk, sm_conn->sm_actual_encryption_key_size,
|
||||
sm_conn->sm_connection_authenticated, sm_conn->sm_connection_authorization_state == AUTHORIZATION_GRANTED);
|
||||
}
|
||||
|
||||
// store encryption infromation for legacy pairing: peer LTK, EDIV, RAND
|
||||
else if ( (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION)
|
||||
&& (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION )){
|
||||
log_info("sm: set encryption information (key size %u, authenticatd %u)", sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated);
|
||||
le_device_db_encryption_set(le_db_index, setup->sm_peer_ediv, setup->sm_peer_rand, setup->sm_peer_ltk,
|
||||
sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated, sm_conn->sm_connection_authorization_state == AUTHORIZATION_GRANTED);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// keep le_db_index
|
||||
@ -1379,6 +1378,7 @@ static void sm_sc_cmac_done(uint8_t * hash){
|
||||
|
||||
sm_connection_t * sm_conn = sm_cmac_connection;
|
||||
sm_cmac_connection = NULL;
|
||||
link_key_type_t link_key_type;
|
||||
|
||||
switch (sm_conn->sm_engine_state){
|
||||
case SM_SC_W4_CMAC_FOR_CONFIRMATION:
|
||||
@ -1409,7 +1409,13 @@ static void sm_sc_cmac_done(uint8_t * hash){
|
||||
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_LTK;
|
||||
break;
|
||||
case SM_SC_W4_CALCULATE_F5_LTK:
|
||||
// truncate sm_ltk, but keep full LTK for cross-transport key derivation in sm_local_ltk
|
||||
// Errata Service Release to the Bluetooth Specification: ESR09
|
||||
// E6405 – Cross transport key derivation from a key of size less than 128 bits
|
||||
// Note: When the BR/EDR link key is being derived from the LTK, the derivation is done before the LTK gets masked."
|
||||
memcpy(setup->sm_ltk, hash, 16);
|
||||
memcpy(setup->sm_local_ltk, hash, 16);
|
||||
sm_truncate_key(setup->sm_ltk, sm_conn->sm_actual_encryption_key_size);
|
||||
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK;
|
||||
break;
|
||||
case SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK:
|
||||
@ -1438,6 +1444,23 @@ static void sm_sc_cmac_done(uint8_t * hash){
|
||||
sm_conn->sm_engine_state = SM_INITIATOR_PH3_SEND_START_ENCRYPTION;
|
||||
}
|
||||
break;
|
||||
case SM_SC_W4_CALCULATE_H6_ILK:
|
||||
memcpy(setup->sm_t, hash, 16);
|
||||
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_H6_BR_EDR_LINK_KEY;
|
||||
break;
|
||||
case SM_SC_W4_CALCULATE_H6_BR_EDR_LINK_KEY:
|
||||
reverse_128(hash, setup->sm_t);
|
||||
link_key_type = sm_conn->sm_connection_authenticated ?
|
||||
AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256 : UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256;
|
||||
if (sm_conn->sm_role){
|
||||
gap_store_link_key_for_bd_addr(setup->sm_m_address, setup->sm_t, link_key_type);
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
|
||||
} else {
|
||||
gap_store_link_key_for_bd_addr(setup->sm_s_address, setup->sm_t, link_key_type);
|
||||
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
|
||||
}
|
||||
sm_done_for_handle(sm_conn->sm_handle);
|
||||
break;
|
||||
default:
|
||||
log_error("sm_sc_cmac_done in state %u", sm_conn->sm_engine_state);
|
||||
break;
|
||||
@ -1474,12 +1497,12 @@ static void sm_sc_calculate_dhkey(sm_key256_t dhkey){
|
||||
mbedtls_mpi_read_binary(&d, ec_d, 32);
|
||||
mbedtls_mpi_read_binary(&Q.X, setup->sm_peer_qx, 32);
|
||||
mbedtls_mpi_read_binary(&Q.Y, setup->sm_peer_qy, 32);
|
||||
mbedtls_mpi_read_string(&Q.Z, 16, "1" );
|
||||
mbedtls_mpi_lset(&Q.Z, 1);
|
||||
mbedtls_ecp_mul(&mbedtls_ec_group, &DH, &d, &Q, NULL, NULL);
|
||||
mbedtls_mpi_write_binary(&DH.X, dhkey, 32);
|
||||
mbedtls_ecp_point_free(&DH);
|
||||
mbedtls_mpi_free(&d);
|
||||
mbedtls_ecp_point_free(&Q);
|
||||
mbedtls_ecp_point_free(&DH);
|
||||
#endif
|
||||
log_info("dhkey");
|
||||
log_info_hexdump(dhkey, 32);
|
||||
@ -1578,7 +1601,7 @@ static void g2_engine(sm_connection_t * sm_conn, const sm_key256_t u, const sm_k
|
||||
log_info("g2 key");
|
||||
log_info_hexdump(x, 16);
|
||||
log_info("g2 message");
|
||||
log_info_hexdump(sm_cmac_sc_buffer, sizeof(sm_cmac_sc_buffer));
|
||||
log_info_hexdump(sm_cmac_sc_buffer, message_len);
|
||||
sm_cmac_general_start(x, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done);
|
||||
}
|
||||
|
||||
@ -1667,8 +1690,48 @@ static void sm_sc_calculate_f6_to_verify_dhkey_check(sm_connection_t * sm_conn){
|
||||
f6_engine(sm_conn, setup->sm_mackey, setup->sm_peer_nonce, setup->sm_local_nonce, setup->sm_ra, iocap_b, bd_addr_slave, bd_addr_master);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Link Key Conversion Function h6
|
||||
//
|
||||
// h6(W, keyID) = AES-CMACW(keyID)
|
||||
// - W is 128 bits
|
||||
// - keyID is 32 bits
|
||||
static void h6_engine(sm_connection_t * sm_conn, const sm_key_t w, const uint32_t key_id){
|
||||
const uint16_t message_len = 4;
|
||||
sm_cmac_connection = sm_conn;
|
||||
big_endian_store_32(sm_cmac_sc_buffer, 0, key_id);
|
||||
log_info("h6 key");
|
||||
log_info_hexdump(w, 16);
|
||||
log_info("h6 message");
|
||||
log_info_hexdump(sm_cmac_sc_buffer, message_len);
|
||||
sm_cmac_general_start(w, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done);
|
||||
}
|
||||
|
||||
// For SC, setup->sm_local_ltk holds full LTK (sm_ltk is already truncated)
|
||||
// Errata Service Release to the Bluetooth Specification: ESR09
|
||||
// E6405 – Cross transport key derivation from a key of size less than 128 bits
|
||||
// "Note: When the BR/EDR link key is being derived from the LTK, the derivation is done before the LTK gets masked."
|
||||
static void h6_calculate_ilk(sm_connection_t * sm_conn){
|
||||
h6_engine(sm_conn, setup->sm_local_ltk, 0x746D7031); // "tmp1"
|
||||
}
|
||||
|
||||
static void h6_calculate_br_edr_link_key(sm_connection_t * sm_conn){
|
||||
h6_engine(sm_conn, setup->sm_t, 0x6c656272); // "lebr"
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// key management legacy connections:
|
||||
// - potentially two different LTKs based on direction. each device stores LTK provided by peer
|
||||
// - master stores LTK, EDIV, RAND. responder optionally stored master LTK (only if it needs to reconnect)
|
||||
// - initiators reconnects: initiator uses stored LTK, EDIV, RAND generated by responder
|
||||
// - responder reconnects: responder uses LTK receveived from master
|
||||
|
||||
// key management secure connections:
|
||||
// - both devices store same LTK from ECDH key exchange.
|
||||
|
||||
static void sm_load_security_info(sm_connection_t * sm_connection){
|
||||
int encryption_key_size;
|
||||
int authenticated;
|
||||
@ -1683,6 +1746,19 @@ static void sm_load_security_info(sm_connection_t * sm_connection){
|
||||
sm_connection->sm_connection_authorization_state = authorized ? AUTHORIZATION_GRANTED : AUTHORIZATION_UNKNOWN;
|
||||
}
|
||||
|
||||
static void sm_start_calculating_ltk_from_ediv_and_rand(sm_connection_t * sm_connection){
|
||||
memcpy(setup->sm_local_rand, sm_connection->sm_local_rand, 8);
|
||||
setup->sm_local_ediv = sm_connection->sm_local_ediv;
|
||||
// re-establish used key encryption size
|
||||
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand
|
||||
sm_connection->sm_actual_encryption_key_size = (setup->sm_local_rand[7] & 0x0f) + 1;
|
||||
// no db for authenticated flag hack: flag is stored in bit 4 of LSB
|
||||
sm_connection->sm_connection_authenticated = (setup->sm_local_rand[7] & 0x10) >> 4;
|
||||
log_info("sm: received ltk request with key size %u, authenticated %u",
|
||||
sm_connection->sm_actual_encryption_key_size, sm_connection->sm_connection_authenticated);
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH4_Y_GET_ENC;
|
||||
}
|
||||
|
||||
static void sm_run(void){
|
||||
|
||||
btstack_linked_list_iterator_t it;
|
||||
@ -1861,6 +1937,7 @@ static void sm_run(void){
|
||||
done = 0;
|
||||
break;
|
||||
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
|
||||
sm_reset_setup();
|
||||
sm_init_setup(sm_connection);
|
||||
// recover pairing request
|
||||
memcpy(&setup->sm_m_preq, &sm_connection->sm_m_preq, sizeof(sm_pairing_packet_t));
|
||||
@ -1879,44 +1956,43 @@ static void sm_run(void){
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE;
|
||||
break;
|
||||
case SM_INITIATOR_PH0_HAS_LTK:
|
||||
sm_reset_setup();
|
||||
sm_load_security_info(sm_connection);
|
||||
sm_connection->sm_engine_state = SM_INITIATOR_PH0_SEND_START_ENCRYPTION;
|
||||
break;
|
||||
case SM_RESPONDER_PH0_RECEIVED_LTK:
|
||||
case SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST:
|
||||
#ifdef ENABLE_LE_SECURE_CONNECTIONS
|
||||
switch (sm_connection->sm_irk_lookup_state){
|
||||
case IRK_LOOKUP_SUCCEEDED:{
|
||||
sm_load_security_info(sm_connection);
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY;
|
||||
case IRK_LOOKUP_SUCCEEDED:
|
||||
// assuming Secure Connection, we have a stored LTK and the EDIV/RAND are null
|
||||
sm_reset_setup();
|
||||
sm_load_security_info(sm_connection);
|
||||
if (setup->sm_peer_ediv == 0 && sm_is_null_random(setup->sm_peer_rand) && !sm_is_null_key(setup->sm_peer_ltk)){
|
||||
memcpy(setup->sm_ltk, setup->sm_peer_ltk, 16);
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK_REPLY;
|
||||
break;
|
||||
}
|
||||
log_info("LTK Request: ediv & random are empty, but no stored LTK (IRK Lookup Succeeded)");
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
|
||||
// don't lock setup context yet
|
||||
done = 0;
|
||||
break;
|
||||
case IRK_LOOKUP_FAILED:
|
||||
// assume that we don't have a LTK for ediv == 0 and random == null
|
||||
if (sm_connection->sm_local_ediv == 0 && sm_is_null_random(sm_connection->sm_local_rand)){
|
||||
log_info("LTK Request: ediv & random are empty");
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
|
||||
// TODO: no need to lock context yet -> done = 0;
|
||||
break;
|
||||
}
|
||||
// re-establish previously used LTK using Rand and EDIV
|
||||
memcpy(setup->sm_local_rand, sm_connection->sm_local_rand, 8);
|
||||
setup->sm_local_ediv = sm_connection->sm_local_ediv;
|
||||
// re-establish used key encryption size
|
||||
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand
|
||||
sm_connection->sm_actual_encryption_key_size = (setup->sm_local_rand[7] & 0x0f) + 1;
|
||||
// no db for authenticated flag hack: flag is stored in bit 4 of LSB
|
||||
sm_connection->sm_connection_authenticated = (setup->sm_local_rand[7] & 0x10) >> 4;
|
||||
log_info("sm: received ltk request with key size %u, authenticated %u",
|
||||
sm_connection->sm_actual_encryption_key_size, sm_connection->sm_connection_authenticated);
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH4_Y_GET_ENC;
|
||||
log_info("LTK Request: ediv & random are empty, but no stored LTK (IRK Lookup Failed)");
|
||||
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
|
||||
// don't lock setup context yet
|
||||
done = 0;
|
||||
break;
|
||||
default:
|
||||
// just wait until IRK lookup is completed
|
||||
// don't lock sxetup context yet
|
||||
// don't lock setup context yet
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST:
|
||||
sm_reset_setup();
|
||||
sm_init_setup(sm_connection);
|
||||
sm_timeout_start(sm_connection);
|
||||
sm_connection->sm_engine_state = SM_INITIATOR_PH1_SEND_PAIRING_REQUEST;
|
||||
@ -1946,6 +2022,16 @@ static void sm_run(void){
|
||||
sm_connection_t * connection = sm_get_connection_for_handle(sm_active_connection);
|
||||
if (!connection) return;
|
||||
|
||||
// send keypress notifications
|
||||
if (setup->sm_keypress_notification != 0xff){
|
||||
uint8_t buffer[2];
|
||||
buffer[0] = SM_CODE_KEYPRESS_NOTIFICATION;
|
||||
buffer[1] = setup->sm_keypress_notification;
|
||||
setup->sm_keypress_notification = 0xff;
|
||||
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
|
||||
return;
|
||||
}
|
||||
|
||||
sm_key_t plaintext;
|
||||
int key_distribution_flags;
|
||||
|
||||
@ -2014,6 +2100,16 @@ static void sm_run(void){
|
||||
connection->sm_engine_state = SM_SC_W4_CALCULATE_G2;
|
||||
g2_calculate(connection);
|
||||
break;
|
||||
case SM_SC_W2_CALCULATE_H6_ILK:
|
||||
if (!sm_cmac_ready()) break;
|
||||
connection->sm_engine_state = SM_SC_W4_CALCULATE_H6_ILK;
|
||||
h6_calculate_ilk(connection);
|
||||
break;
|
||||
case SM_SC_W2_CALCULATE_H6_BR_EDR_LINK_KEY:
|
||||
if (!sm_cmac_ready()) break;
|
||||
connection->sm_engine_state = SM_SC_W4_CALCULATE_H6_BR_EDR_LINK_KEY;
|
||||
h6_calculate_br_edr_link_key(connection);
|
||||
break;
|
||||
|
||||
#endif
|
||||
// initiator side
|
||||
@ -2293,7 +2389,7 @@ static void sm_run(void){
|
||||
hci_send_cmd(&hci_le_start_encryption, connection->sm_handle, 0, 0, 0, stk_flipped);
|
||||
return;
|
||||
}
|
||||
case SM_RESPONDER_PH4_SEND_LTK: {
|
||||
case SM_RESPONDER_PH4_SEND_LTK_REPLY: {
|
||||
sm_key_t ltk_flipped;
|
||||
reverse_128(setup->sm_ltk, ltk_flipped);
|
||||
connection->sm_engine_state = SM_RESPONDER_IDLE;
|
||||
@ -2540,9 +2636,13 @@ static void sm_handle_encryption_result(uint8_t * data){
|
||||
// slave -> receive master keys
|
||||
connection->sm_engine_state = SM_PH3_RECEIVE_KEYS;
|
||||
} else {
|
||||
// master -> all done
|
||||
connection->sm_engine_state = SM_INITIATOR_CONNECTED;
|
||||
sm_done_for_handle(connection->sm_handle);
|
||||
if (setup->sm_use_secure_connections && (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION)){
|
||||
connection->sm_engine_state = SM_SC_W2_CALCULATE_H6_ILK;
|
||||
} else {
|
||||
// master -> all done
|
||||
connection->sm_engine_state = SM_INITIATOR_CONNECTED;
|
||||
sm_done_for_handle(connection->sm_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -2550,7 +2650,7 @@ static void sm_handle_encryption_result(uint8_t * data){
|
||||
reverse_128(data, setup->sm_ltk);
|
||||
sm_truncate_key(setup->sm_ltk, connection->sm_actual_encryption_key_size);
|
||||
log_info_key("ltk", setup->sm_ltk);
|
||||
connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK;
|
||||
connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK_REPLY;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@ -2590,6 +2690,7 @@ static void sm_handle_random_result(uint8_t * data){
|
||||
setup->sm_passkey_bit = num_bytes;
|
||||
|
||||
if (num_bytes >= 64){
|
||||
|
||||
// generate EC key
|
||||
setup->sm_passkey_bit = 0;
|
||||
mbedtls_mpi d;
|
||||
@ -2607,11 +2708,15 @@ static void sm_handle_random_result(uint8_t * data){
|
||||
sm_log_ec_keypair();
|
||||
|
||||
#if 0
|
||||
printf("test dhkey check\n");
|
||||
int i;
|
||||
sm_key256_t dhkey;
|
||||
memcpy(setup->sm_peer_qx, ec_qx, 32);
|
||||
memcpy(setup->sm_peer_qy, ec_qy, 32);
|
||||
sm_sc_calculate_dhkey(dhkey);
|
||||
for (i=0;i<10;i++){
|
||||
// printf("test dhkey check\n");
|
||||
memcpy(setup->sm_peer_qx, ec_qx, 32);
|
||||
memcpy(setup->sm_peer_qy, ec_qy, 32);
|
||||
sm_sc_calculate_dhkey(dhkey);
|
||||
// printf("test dhkey check end\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -2731,6 +2836,12 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
|
||||
// bt stack activated, get started
|
||||
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
|
||||
log_info("HCI Working!");
|
||||
|
||||
// set local addr for le device db
|
||||
bd_addr_t local_bd_addr;
|
||||
gap_local_bd_addr(local_bd_addr);
|
||||
le_device_db_set_local_bd_addr(local_bd_addr);
|
||||
|
||||
dkg_state = sm_persistent_irk_ready ? DKG_CALC_DHK : DKG_CALC_IRK;
|
||||
rau_state = RAU_IDLE;
|
||||
#ifdef USE_MBEDTLS_FOR_ECDH
|
||||
@ -2802,6 +2913,7 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
|
||||
break;
|
||||
}
|
||||
if (sm_conn->sm_engine_state == SM_SC_W4_LTK_REQUEST_SC){
|
||||
// PH2 SEND LTK as we need to exchange keys in PH3
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY;
|
||||
break;
|
||||
}
|
||||
@ -2809,7 +2921,20 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
|
||||
// store rand and ediv
|
||||
reverse_64(&packet[5], sm_conn->sm_local_rand);
|
||||
sm_conn->sm_local_ediv = little_endian_read_16(packet, 13);
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK;
|
||||
|
||||
// For Legacy Pairing (<=> EDIV != 0 || RAND != NULL), we need to recalculated our LTK as a
|
||||
// potentially stored LTK is from the master
|
||||
if (sm_conn->sm_local_ediv != 0 || !sm_is_null_random(sm_conn->sm_local_rand)){
|
||||
sm_start_calculating_ltk_from_ediv_and_rand(sm_conn);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LE_SECURE_CONNECTIONS
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST;
|
||||
#else
|
||||
log_info("LTK Request: ediv & random are empty, but LE Secure Connections not supported");
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2994,6 +3119,16 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
|
||||
|
||||
int err;
|
||||
|
||||
if (packet[0] == SM_CODE_KEYPRESS_NOTIFICATION){
|
||||
uint8_t buffer[5];
|
||||
buffer[0] = SM_EVENT_KEYPRESS_NOTIFICATION;
|
||||
buffer[1] = 3;
|
||||
little_endian_store_16(buffer, 2, con_handle);
|
||||
buffer[4] = packet[1];
|
||||
sm_dispatch_event(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sm_conn->sm_engine_state){
|
||||
|
||||
// a sm timeout requries a new physical connection
|
||||
@ -3011,10 +3146,9 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
|
||||
break;
|
||||
}
|
||||
if (sm_conn->sm_irk_lookup_state == IRK_LOOKUP_SUCCEEDED){
|
||||
uint16_t ediv;
|
||||
sm_key_t ltk;
|
||||
le_device_db_encryption_get(sm_conn->sm_le_db_index, &ediv, NULL, ltk, NULL, NULL, NULL);
|
||||
if (!sm_is_null_key(ltk) || ediv){
|
||||
le_device_db_encryption_get(sm_conn->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL);
|
||||
if (!sm_is_null_key(ltk)){
|
||||
log_info("sm: Setting up previous ltk/ediv/rand for device index %u", sm_conn->sm_le_db_index);
|
||||
sm_conn->sm_engine_state = SM_INITIATOR_PH0_HAS_LTK;
|
||||
} else {
|
||||
@ -3122,7 +3256,7 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
|
||||
mbedtls_ecp_point_init( &Q );
|
||||
mbedtls_mpi_read_binary(&Q.X, setup->sm_peer_qx, 32);
|
||||
mbedtls_mpi_read_binary(&Q.Y, setup->sm_peer_qy, 32);
|
||||
mbedtls_mpi_read_string(&Q.Z, 16, "1" );
|
||||
mbedtls_mpi_lset(&Q.Z, 1);
|
||||
err = mbedtls_ecp_check_pubkey(&mbedtls_ec_group, &Q);
|
||||
mbedtls_ecp_point_free( & Q);
|
||||
if (err){
|
||||
@ -3316,8 +3450,12 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
|
||||
sm_key_distribution_handle_all_received(sm_conn);
|
||||
|
||||
if (sm_conn->sm_role){
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
|
||||
sm_done_for_handle(sm_conn->sm_handle);
|
||||
if (setup->sm_use_secure_connections && (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION)){
|
||||
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_H6_ILK;
|
||||
} else {
|
||||
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
|
||||
sm_done_for_handle(sm_conn->sm_handle);
|
||||
}
|
||||
} else {
|
||||
if (setup->sm_use_secure_connections){
|
||||
sm_conn->sm_engine_state = SM_PH3_DISTRIBUTE_KEYS;
|
||||
@ -3435,7 +3573,6 @@ void sm_init(void){
|
||||
#endif
|
||||
mbedtls_ecp_group_init(&mbedtls_ec_group);
|
||||
mbedtls_ecp_group_load(&mbedtls_ec_group, MBEDTLS_ECP_DP_SECP256R1);
|
||||
|
||||
#if 0
|
||||
// test
|
||||
sm_test_use_fixed_ec_keypair();
|
||||
@ -3652,6 +3789,14 @@ void sm_passkey_input(hci_con_handle_t con_handle, uint32_t passkey){
|
||||
sm_run();
|
||||
}
|
||||
|
||||
void sm_keypress_notification(hci_con_handle_t con_handle, uint8_t action){
|
||||
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
|
||||
if (!sm_conn) return; // wrong connection
|
||||
if (action > SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED) return;
|
||||
setup->sm_keypress_notification = action;
|
||||
sm_run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Identify device in LE Device DB
|
||||
* @param handle
|
||||
|
37
src/ble/sm.h
37
src/ble/sm.h
@ -189,6 +189,13 @@ void sm_numeric_comparison_confirm(hci_con_handle_t con_handle);
|
||||
*/
|
||||
void sm_passkey_input(hci_con_handle_t con_handle, uint32_t passkey);
|
||||
|
||||
/**
|
||||
* @brief Send keypress notification for keyboard only devices
|
||||
* @param con_handle
|
||||
* @param action see SM_KEYPRESS_* in bluetooth.h
|
||||
*/
|
||||
void sm_keypress_notification(hci_con_handle_t con_handle, uint8_t action);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Get encryption key size.
|
||||
@ -229,6 +236,23 @@ void sm_authorization_decline(hci_con_handle_t con_handle);
|
||||
*/
|
||||
void sm_authorization_grant(hci_con_handle_t con_handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if CMAC AES engine is ready
|
||||
* @return ready
|
||||
*/
|
||||
int sm_cmac_ready(void);
|
||||
|
||||
/*
|
||||
* @brief Generic CMAC AES
|
||||
* @param key
|
||||
* @param message_len
|
||||
* @param get_byte_callback
|
||||
* @param done_callback
|
||||
* @note hash is 16 bytes in big endian
|
||||
*/
|
||||
void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*get_byte_callback)(uint16_t offset), void (*done_callback)(uint8_t * hash));
|
||||
|
||||
/**
|
||||
* @brief Support for signed writes, used by att_server.
|
||||
* @note Message is in little endian to allows passing in ATT PDU without flipping.
|
||||
@ -241,18 +265,7 @@ void sm_authorization_grant(hci_con_handle_t con_handle);
|
||||
* @param message
|
||||
* @param sign_counter
|
||||
*/
|
||||
int sm_cmac_ready(void);
|
||||
void sm_cmac_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash));
|
||||
|
||||
/*
|
||||
* @brief Generic CMAC AES
|
||||
* @param key
|
||||
* @param message_len
|
||||
* @param get_byte_callback
|
||||
* @param done_callback
|
||||
* @note hash is 16 bytes in big endian
|
||||
*/
|
||||
void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*get_byte_callback)(uint16_t offset), void (*done_callback)(uint8_t * hash));
|
||||
void sm_cmac_signed_write_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash));
|
||||
|
||||
/*
|
||||
* @brief Match address against bonded devices
|
||||
|
@ -954,6 +954,7 @@ typedef enum {
|
||||
SM_CODE_SECURITY_REQUEST,
|
||||
SM_CODE_PAIRING_PUBLIC_KEY,
|
||||
SM_CODE_PAIRING_DHKEY_CHECK,
|
||||
SM_CODE_KEYPRESS_NOTIFICATION,
|
||||
} SECURITY_MANAGER_COMMANDS;
|
||||
|
||||
// IO Capability Values
|
||||
@ -1009,6 +1010,14 @@ typedef enum {
|
||||
// also, invalid parameters
|
||||
// and reserved
|
||||
|
||||
// Keypress Notifications
|
||||
#define SM_KEYPRESS_PASSKEY_ENTRY_STARTED 0x00
|
||||
#define SM_KEYPRESS_PASSKEY_DIGIT_ENTERED 0x01
|
||||
#define SM_KEYPRESS_PASSKEY_DIGIT_ERASED 0x02
|
||||
#define SM_KEYPRESS_PASSKEY_CLEARED 0x03
|
||||
#define SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED 0x04
|
||||
|
||||
|
||||
// Company identifiers / manufacturers
|
||||
#define COMPANY_ID_CAMBRIDGE_SILICON_RADIO 0x000A
|
||||
#define COMPANY_ID_TEXAS_INSTRUMENTS_INC 0x000D
|
||||
|
@ -793,6 +793,14 @@ typedef uint8_t sm_key_t[16];
|
||||
*/
|
||||
#define SM_EVENT_AUTHORIZATION_RESULT 0xDC
|
||||
|
||||
/**
|
||||
* @format H1
|
||||
* @param handle
|
||||
* @param action see SM_KEYPRESS_*
|
||||
*/
|
||||
#define SM_EVENT_KEYPRESS_NOTIFICATION 0xDD
|
||||
|
||||
|
||||
// GAP
|
||||
|
||||
/**
|
||||
|
@ -2417,6 +2417,27 @@ static inline uint8_t sm_event_authorization_result_get_authorization_result(con
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BLE
|
||||
/**
|
||||
* @brief Get field handle from event SM_EVENT_KEYPRESS_NOTIFICATION
|
||||
* @param event packet
|
||||
* @return handle
|
||||
* @note: btstack_type H
|
||||
*/
|
||||
static inline hci_con_handle_t sm_event_keypress_notification_get_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 2);
|
||||
}
|
||||
/**
|
||||
* @brief Get field action from event SM_EVENT_KEYPRESS_NOTIFICATION
|
||||
* @param event packet
|
||||
* @return action
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t sm_event_keypress_notification_get_action(const uint8_t * event){
|
||||
return event[4];
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get field handle from event GAP_EVENT_SECURITY_LEVEL
|
||||
* @param event packet
|
||||
|
@ -44,10 +44,11 @@
|
||||
*/
|
||||
|
||||
#include "btstack_config.h"
|
||||
#include "btstack_debug.h"
|
||||
#include "btstack_util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "btstack_debug.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -171,17 +172,12 @@ void printf_hexdump(const void *data, int size){
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// void log_info_hexdump(..){
|
||||
//
|
||||
// }
|
||||
|
||||
void log_info_hexdump(const void *data, int size){
|
||||
#ifdef ENABLE_LOG_INFO
|
||||
char buffer[6*16+1];
|
||||
int i, j;
|
||||
|
||||
uint8_t low = 0x0F;
|
||||
uint8_t high = 0xF0;
|
||||
const uint8_t low = 0x0F;
|
||||
const uint8_t high = 0xF0;
|
||||
j = 0;
|
||||
for (i=0; i<size;i++){
|
||||
uint8_t byte = ((uint8_t *)data)[i];
|
||||
@ -205,8 +201,20 @@ void log_info_hexdump(const void *data, int size){
|
||||
}
|
||||
|
||||
void log_info_key(const char * name, sm_key_t key){
|
||||
// log_info("%-6s ", name);
|
||||
// hexdump(key, 16);
|
||||
#ifdef ENABLE_LOG_INFO
|
||||
char buffer[16*2+1];
|
||||
const uint8_t low = 0x0F;
|
||||
const uint8_t high = 0xF0;
|
||||
int i;
|
||||
int j = 0;
|
||||
for (i=0; i<16;i++){
|
||||
uint8_t byte = key[i];
|
||||
buffer[j++] = char_for_nibble((byte & high) >> 4);
|
||||
buffer[j++] = char_for_nibble(byte & low);
|
||||
}
|
||||
buffer[j] = 0;
|
||||
log_info("%-6s %s", name, buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// UUIDs are stored in big endian, similar to bd_addr_t
|
||||
|
@ -353,9 +353,18 @@ void gap_local_bd_addr(bd_addr_t address_buffer);
|
||||
|
||||
/**
|
||||
* @brief Deletes link key for remote device with baseband address.
|
||||
* @param addr
|
||||
*/
|
||||
void gap_drop_link_key_for_bd_addr(bd_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief Store link key for remote device with baseband address
|
||||
* @param addr
|
||||
* @param link_key
|
||||
* @param link_key_type
|
||||
*/
|
||||
void gap_store_link_key_for_bd_addr(bd_addr_t addr, link_key_t link_key, link_key_type_t type);
|
||||
|
||||
// LE
|
||||
|
||||
/**
|
||||
|
16
src/hci.c
16
src/hci.c
@ -263,9 +263,15 @@ int hci_authentication_active_for_handle(hci_con_handle_t handle){
|
||||
}
|
||||
|
||||
void gap_drop_link_key_for_bd_addr(bd_addr_t addr){
|
||||
if (hci_stack->link_key_db) {
|
||||
hci_stack->link_key_db->delete_link_key(addr);
|
||||
}
|
||||
if (!hci_stack->link_key_db) return;
|
||||
log_info("gap_drop_link_key_for_bd_addr: %s", bd_addr_to_str(addr));
|
||||
hci_stack->link_key_db->delete_link_key(addr);
|
||||
}
|
||||
|
||||
void gap_store_link_key_for_bd_addr(bd_addr_t addr, link_key_t link_key, link_key_type_t type){
|
||||
if (!hci_stack->link_key_db) return;
|
||||
log_info("gap_store_link_key_for_bd_addr: %s, type %u", bd_addr_to_str(addr), type);
|
||||
hci_stack->link_key_db->put_link_key(addr, link_key, type);
|
||||
}
|
||||
|
||||
static int hci_is_le_connection(hci_connection_t * connection){
|
||||
@ -273,7 +279,6 @@ static int hci_is_le_connection(hci_connection_t * connection){
|
||||
connection->address_type == BD_ADDR_TYPE_LE_RANDOM;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* count connections
|
||||
*/
|
||||
@ -1631,8 +1636,7 @@ static void event_handler(uint8_t *packet, int size){
|
||||
if (link_key_type != CHANGED_COMBINATION_KEY){
|
||||
conn->link_key_type = link_key_type;
|
||||
}
|
||||
if (!hci_stack->link_key_db) break;
|
||||
hci_stack->link_key_db->put_link_key(addr, &packet[8], conn->link_key_type);
|
||||
gap_store_link_key_for_bd_addr(addr, &packet[8], conn->link_key_type);
|
||||
// still forward event to allow dismiss of pairing dialog
|
||||
break;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ typedef enum {
|
||||
// state = 35
|
||||
SM_RESPONDER_IDLE,
|
||||
SM_RESPONDER_SEND_SECURITY_REQUEST,
|
||||
SM_RESPONDER_PH0_RECEIVED_LTK,
|
||||
SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST,
|
||||
SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY,
|
||||
SM_RESPONDER_PH1_W4_PAIRING_REQUEST,
|
||||
SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED,
|
||||
@ -287,7 +287,7 @@ typedef enum {
|
||||
SM_RESPONDER_PH4_Y_W4_ENC,
|
||||
SM_RESPONDER_PH4_LTK_GET_ENC,
|
||||
SM_RESPONDER_PH4_LTK_W4_ENC,
|
||||
SM_RESPONDER_PH4_SEND_LTK,
|
||||
SM_RESPONDER_PH4_SEND_LTK_REPLY,
|
||||
|
||||
// INITITIATOR ROLE
|
||||
// state = 51
|
||||
@ -333,7 +333,10 @@ typedef enum {
|
||||
SM_SC_SEND_DHKEY_CHECK_COMMAND,
|
||||
SM_SC_W4_DHKEY_CHECK_COMMAND,
|
||||
SM_SC_W4_LTK_REQUEST_SC,
|
||||
|
||||
SM_SC_W2_CALCULATE_H6_ILK,
|
||||
SM_SC_W4_CALCULATE_H6_ILK,
|
||||
SM_SC_W2_CALCULATE_H6_BR_EDR_LINK_KEY,
|
||||
SM_SC_W4_CALCULATE_H6_BR_EDR_LINK_KEY,
|
||||
} security_manager_state_t;
|
||||
|
||||
typedef enum {
|
||||
|
2
test/btstack_link_key_db/.gitignore
vendored
2
test/btstack_link_key_db/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
remote_device_db_fs_test
|
||||
remote_device_db_memory_test
|
||||
btstack_link_key_db_fs_test
|
||||
btstack_link_key_db_memory_test
|
@ -121,7 +121,7 @@ int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t l
|
||||
int sm_cmac_ready(void){
|
||||
return 1;
|
||||
}
|
||||
void sm_cmac_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash)){
|
||||
void sm_cmac_signed_write_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash)){
|
||||
//sm_notify_client(SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED, sm_central_device_addr_type, sm_central_device_address, 0, sm_central_device_matched);
|
||||
}
|
||||
int sm_le_device_index(uint16_t handle ){
|
||||
|
@ -3,7 +3,7 @@ BTSTACK_ROOT = ../..
|
||||
|
||||
CORE += main.c stdin_support.c
|
||||
|
||||
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c
|
||||
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c le_device_db_fs.c
|
||||
|
||||
include ${BTSTACK_ROOT}/example/Makefile.inc
|
||||
|
||||
|
@ -1457,7 +1457,7 @@ static void ui_process_command(char buffer){
|
||||
// fetch csrk
|
||||
le_device_db_local_csrk_get(le_device_db_index, signing_csrk);
|
||||
// calc signature
|
||||
sm_cmac_start(signing_csrk, ATT_SIGNED_WRITE_COMMAND, pts_signed_write_characteristic_handle, sizeof(signed_write_value), signed_write_value, 0, att_signed_write_handle_cmac_result);
|
||||
sm_cmac_signed_write_start(signing_csrk, ATT_SIGNED_WRITE_COMMAND, pts_signed_write_characteristic_handle, sizeof(signed_write_value), signed_write_value, 0, att_signed_write_handle_cmac_result);
|
||||
break;
|
||||
case 'x':
|
||||
sm_min_key_size = 7;
|
||||
|
@ -97,7 +97,7 @@ void mock_simulate_sm_data_packet(uint8_t * packet, uint16_t len){
|
||||
}
|
||||
|
||||
void mock_simulate_command_complete(const hci_cmd_t *cmd){
|
||||
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, cmd->opcode & 0xff, cmd->opcode >> 8, 0};
|
||||
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, (uint8_t) cmd->opcode & 0xff, (uint8_t) cmd->opcode >> 8, 0};
|
||||
mock_simulate_hci_event((uint8_t *)&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
@ -118,6 +118,12 @@ void att_init_connection(att_connection_t * att_connection){
|
||||
att_connection->authorized = 0;
|
||||
}
|
||||
|
||||
void gap_local_bd_addr(bd_addr_t address_buffer){
|
||||
int i;
|
||||
for (i=0;i<6;i++) {
|
||||
address_buffer[i] = 0x11 * (i+1);
|
||||
}
|
||||
}
|
||||
int hci_can_send_command_packet_now(void){
|
||||
return 1;
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ TEST(SecurityManager, CMACTest){
|
||||
parse_hex(key, key_string);
|
||||
uint8_t message [] = "hallo";
|
||||
cmac_hash_received = 0;
|
||||
sm_cmac_start(key, 0x11, 0x1234, sizeof(message), message, 1, &cmac_done);
|
||||
sm_cmac_signed_write_start(key, 0x11, 0x1234, sizeof(message), message, 1, &cmac_done);
|
||||
while (!cmac_hash_received){
|
||||
aes128_report_result();
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ static inline uint8_t hci_event_{meta_event}_meta_get_subevent_code(const uint8_
|
||||
'''
|
||||
|
||||
# global variables/defines
|
||||
gen_path = '../src/btstack_event.h'
|
||||
# gen_path = '../src/btstack_event.h'
|
||||
|
||||
defines = dict()
|
||||
defines_used = set()
|
||||
@ -264,8 +264,8 @@ def create_events(events):
|
||||
|
||||
fout.write(hfile_header_end)
|
||||
|
||||
# set root
|
||||
parser.set_btstack_root('..')
|
||||
btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..')
|
||||
gen_path = btstack_root + '/src/btstack_event.h'
|
||||
|
||||
print(program_info)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user