2014-01-05 19:21:33 +00:00
/*
2015-02-06 16:19:27 +00:00
* Copyright ( C ) 2014 BlueKitchen GmbH
2014-01-05 19:21:33 +00:00
*
* 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 .
*
2015-02-06 16:19:27 +00:00
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2014-01-05 19:21:33 +00:00
* ` ` 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 .
*
2015-02-06 16:19:27 +00:00
* Please inquire about commercial licensing options at
* contact @ bluekitchen - gmbh . com
2014-01-05 19:21:33 +00:00
*
*/
# include <stdio.h>
2014-04-03 21:40:48 +00:00
# include <string.h>
2014-01-05 19:21:33 +00:00
2015-02-12 15:27:54 +00:00
# include <btstack/linked_list.h>
2014-01-05 19:21:33 +00:00
# include "debug.h"
# include "hci.h"
# include "l2cap.h"
2015-03-02 21:40:56 +00:00
# include "le_device_db.h"
2014-01-05 20:13:37 +00:00
# include "sm.h"
# include "gap_le.h"
2014-01-05 19:21:33 +00:00
//
// SM internal types and globals
//
typedef enum {
DKG_W4_WORKING ,
DKG_CALC_IRK ,
DKG_W4_IRK ,
DKG_CALC_DHK ,
DKG_W4_DHK ,
DKG_READY
} derived_key_generation_t ;
typedef enum {
2015-02-27 15:53:53 +00:00
RAU_W4_WORKING ,
2014-01-05 19:21:33 +00:00
RAU_IDLE ,
RAU_GET_RANDOM ,
RAU_W4_RANDOM ,
RAU_GET_ENC ,
RAU_W4_ENC ,
RAU_SET_ADDRESS ,
} random_address_update_t ;
typedef enum {
CMAC_IDLE ,
CMAC_CALC_SUBKEYS ,
CMAC_W4_SUBKEYS ,
CMAC_CALC_MI ,
CMAC_W4_MI ,
CMAC_CALC_MLAST ,
CMAC_W4_MLAST
} cmac_state_t ;
typedef enum {
JUST_WORKS ,
PK_RESP_INPUT , // Initiator displays PK, initiator inputs PK
PK_INIT_INPUT , // Responder displays PK, responder inputs PK
OK_BOTH_INPUT , // Only input on both, both input PK
OOB // OOB available on both sides
} stk_generation_method_t ;
typedef enum {
SM_USER_RESPONSE_IDLE ,
SM_USER_RESPONSE_PENDING ,
SM_USER_RESPONSE_CONFIRM ,
SM_USER_RESPONSE_PASSKEY ,
SM_USER_RESPONSE_DECLINE
} sm_user_response_t ;
2014-06-12 13:38:17 +00:00
typedef enum {
SM_AES128_IDLE ,
SM_AES128_ACTIVE
} sm_aes128_state_t ;
2014-06-12 21:54:00 +00:00
2014-01-05 19:21:33 +00:00
//
// GLOBAL DATA
//
2014-06-12 15:07:01 +00:00
// configuration
static uint8_t sm_accepted_stk_generation_methods ;
static uint8_t sm_max_encryption_key_size ;
static uint8_t sm_min_encryption_key_size ;
2014-06-12 22:15:27 +00:00
static uint8_t sm_auth_req = 0 ;
2014-10-16 13:56:25 +00:00
static uint8_t sm_io_capabilities = IO_CAPABILITY_NO_INPUT_NO_OUTPUT ;
2014-06-12 21:54:00 +00:00
static uint8_t sm_slave_request_security ;
2014-06-13 09:53:46 +00:00
static uint8_t sm_authenticate_outgoing_connections = 0 ; // might go away
2014-06-12 15:07:01 +00:00
2014-01-05 19:21:33 +00:00
// Security Manager Master Keys, please use sm_set_er(er) and sm_set_ir(ir) with your own 128 bit random values
static sm_key_t sm_persistent_er ;
static sm_key_t sm_persistent_ir ;
// derived from sm_persistent_ir
static sm_key_t sm_persistent_dhk ;
static sm_key_t sm_persistent_irk ;
2014-02-02 18:45:00 +00:00
static uint8_t sm_persistent_irk_ready = 0 ; // used for testing
2015-02-27 15:53:53 +00:00
static derived_key_generation_t dkg_state ;
2014-01-05 19:21:33 +00:00
// derived from sm_persistent_er
// ..
// random address update
2015-02-27 15:53:53 +00:00
static random_address_update_t rau_state ;
2014-01-05 19:21:33 +00:00
static bd_addr_t sm_random_address ;
2014-06-12 21:54:00 +00:00
// CMAC calculation
2014-06-12 15:07:01 +00:00
static cmac_state_t sm_cmac_state ;
static sm_key_t sm_cmac_k ;
static uint16_t sm_cmac_message_len ;
static uint8_t * sm_cmac_message ;
2015-03-05 14:42:26 +00:00
static uint8_t sm_cmac_sign_counter [ 4 ] ;
2014-06-12 15:07:01 +00:00
static sm_key_t sm_cmac_m_last ;
static sm_key_t sm_cmac_x ;
static uint8_t sm_cmac_block_current ;
static uint8_t sm_cmac_block_count ;
static void ( * sm_cmac_done_handler ) ( uint8_t hash [ 8 ] ) ;
2014-01-05 19:21:33 +00:00
2014-06-12 21:54:00 +00:00
// resolvable private address lookup
2014-06-12 15:07:01 +00:00
static int sm_central_device_test ;
static int sm_central_device_matched ;
static int sm_central_ah_calculation_active ;
static uint8_t sm_central_device_addr_type ;
static bd_addr_t sm_central_device_address ;
2014-01-05 19:21:33 +00:00
2015-02-12 16:16:42 +00:00
// aes128 crypto engine. store current sm_connection_t in sm_aes128_connection_source
static sm_aes128_state_t sm_aes128_state ;
static sm_connection_t * sm_aes128_connection_source ;
// random engine. store current sm_connection_t in sm_random
static sm_connection_t * sm_random_connection_source ;
2014-01-05 19:21:33 +00:00
2015-02-12 21:36:06 +00:00
// CSRK calculation
static sm_connection_t * sm_csrk_connection_source ;
2014-01-05 19:21:33 +00:00
//
// Volume 3, Part H, Chapter 24
// "Security shall be initiated by the Security Manager in the device in the master role.
// The device in the slave role shall be the responding device."
// -> master := initiator, slave := responder
//
2014-06-12 21:54:00 +00:00
// data needed for security setup
2014-06-12 21:16:47 +00:00
typedef struct sm_setup_context {
2014-06-14 21:11:34 +00:00
2015-02-27 14:17:45 +00:00
timer_source_t sm_timeout ;
2014-06-15 10:55:02 +00:00
// used in all phases
2014-06-12 21:16:47 +00:00
uint8_t sm_pairing_failed_reason ;
2014-06-15 10:55:02 +00:00
// user response, (Phase 1 and/or 2)
2014-06-14 21:11:34 +00:00
uint8_t sm_user_response ;
2014-06-13 10:19:18 +00:00
2014-06-15 10:55:02 +00:00
// defines which keys will be send after connection is encrypted - calculated during Phase 1, used Phase 3
int sm_key_distribution_send_set ;
int sm_key_distribution_received_set ;
// Phase 2 (Pairing over SMP)
2014-06-14 21:11:34 +00:00
stk_generation_method_t sm_stk_generation_method ;
sm_key_t sm_tk ;
2014-06-13 12:42:10 +00:00
2014-06-15 10:55:02 +00:00
sm_key_t sm_c1_t3_value ; // c1 calculation
2014-06-14 21:11:34 +00:00
sm_pairing_packet_t sm_m_preq ; // pairing request - needed only for c1
sm_pairing_packet_t sm_s_pres ; // pairing response - needed only for c1
2014-06-13 13:31:16 +00:00
sm_key_t sm_local_random ;
sm_key_t sm_local_confirm ;
2014-06-14 21:11:34 +00:00
sm_key_t sm_peer_random ;
sm_key_t sm_peer_confirm ;
2014-06-15 10:55:02 +00:00
uint8_t sm_m_addr_type ; // address and type can be removed
uint8_t sm_s_addr_type ; // ''
bd_addr_t sm_m_address ; // ''
bd_addr_t sm_s_address ; // ''
2014-06-14 21:11:34 +00:00
sm_key_t sm_ltk ;
2014-06-15 10:55:02 +00:00
// Phase 3
2014-06-14 21:11:34 +00:00
2014-06-13 18:37:12 +00:00
// key distribution, we generate
uint16_t sm_local_y ;
uint16_t sm_local_div ;
uint16_t sm_local_ediv ;
uint8_t sm_local_rand [ 8 ] ;
sm_key_t sm_local_ltk ;
sm_key_t sm_local_csrk ;
sm_key_t sm_local_irk ;
2014-06-14 20:45:50 +00:00
// sm_local_address/addr_type not needed
2014-06-13 18:37:12 +00:00
// key distribution, received from peer
uint16_t sm_peer_y ;
uint16_t sm_peer_div ;
uint16_t sm_peer_ediv ;
uint8_t sm_peer_rand [ 8 ] ;
sm_key_t sm_peer_ltk ;
sm_key_t sm_peer_irk ;
2015-03-02 21:12:29 +00:00
sm_key_t sm_peer_csrk ;
2014-06-14 20:45:50 +00:00
uint8_t sm_peer_addr_type ;
bd_addr_t sm_peer_address ;
2015-03-02 21:12:29 +00:00
2014-06-12 21:16:47 +00:00
} sm_setup_context_t ;
2014-06-12 15:07:01 +00:00
2014-06-12 21:16:47 +00:00
//
2014-06-13 08:59:47 +00:00
static sm_setup_context_t the_setup ;
static sm_setup_context_t * setup = & the_setup ;
2014-01-05 19:21:33 +00:00
2015-02-26 16:11:09 +00:00
// active connection - the one for which the_setup is used for
static uint16_t sm_active_connection = 0 ;
2014-01-05 19:21:33 +00:00
// @returns 1 if oob data is available
// stores oob data in provided 16 byte buffer if not null
2015-03-01 20:51:08 +00:00
static int ( * sm_get_oob_data ) ( uint8_t addres_type , bd_addr_t addr , uint8_t * oob_data ) = NULL ;
2014-01-05 19:21:33 +00:00
// 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 ] = {
{ JUST_WORKS , JUST_WORKS , PK_INIT_INPUT , JUST_WORKS , PK_INIT_INPUT } ,
{ JUST_WORKS , JUST_WORKS , PK_INIT_INPUT , JUST_WORKS , PK_INIT_INPUT } ,
{ PK_RESP_INPUT , PK_RESP_INPUT , OK_BOTH_INPUT , JUST_WORKS , PK_RESP_INPUT } ,
{ JUST_WORKS , JUST_WORKS , JUST_WORKS , JUST_WORKS , JUST_WORKS } ,
{ PK_RESP_INPUT , PK_RESP_INPUT , PK_INIT_INPUT , JUST_WORKS , PK_RESP_INPUT } ,
} ;
2015-04-28 10:31:53 -04:00
static void sm_run ( void ) ;
2015-02-26 16:11:09 +00:00
static void sm_done_for_handle ( uint16_t handle ) ;
2014-06-12 15:07:01 +00:00
static void sm_notify_client ( uint8_t type , uint8_t addr_type , bd_addr_t address , uint32_t passkey , uint16_t index ) ;
2015-02-12 23:04:15 +00:00
static sm_connection_t * sm_get_connection_for_handle ( uint16_t handle ) ;
2015-02-26 21:32:16 +00:00
static inline int sm_calc_actual_encryption_key_size ( int other ) ;
2015-04-28 10:31:53 -04:00
static int sm_validate_stk_generation_method ( void ) ;
2014-01-05 19:21:33 +00:00
2014-08-15 21:26:50 +00:00
static void log_info_hex16 ( const char * name , uint16_t value ) {
log_info ( " %-6s 0x%04x " , name , value ) ;
2014-01-05 19:21:33 +00:00
}
// @returns 1 if all bytes are 0
static int sm_is_null_random ( uint8_t random [ 8 ] ) {
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( random [ i ] ) return 0 ;
}
return 1 ;
}
// Key utils
2015-05-13 10:30:46 +02:00
static void sm_reset_tk ( void ) {
2014-01-05 19:21:33 +00:00
int i ;
for ( i = 0 ; i < 16 ; i + + ) {
2014-06-12 21:16:47 +00:00
setup - > sm_tk [ i ] = 0 ;
2014-01-05 19:21:33 +00:00
}
}
// "For example, if a 128-bit encryption key is 0x123456789ABCDEF0123456789ABCDEF0
// and it is reduced to 7 octets (56 bits), then the resulting key is 0x0000000000000000003456789ABCDEF0.""
static void sm_truncate_key ( sm_key_t key , int max_encryption_size ) {
int i ;
for ( i = max_encryption_size ; i < 16 ; i + + ) {
key [ 15 - i ] = 0 ;
}
}
// SMP Timeout implementation
// Upon transmission of the Pairing Request command or reception of the Pairing Request command,
// the Security Manager Timer shall be reset and started.
//
// The Security Manager Timer shall be reset when an L2CAP SMP command is queued for transmission.
//
// If the Security Manager Timer reaches 30 seconds, the procedure shall be considered to have failed,
// and the local higher layer shall be notified. No further SMP commands shall be sent over the L2CAP
// Security Manager Channel. A new SM procedure shall only be performed when a new physical link has been
// established.
2015-02-27 14:17:45 +00:00
static void sm_timeout_handler ( timer_source_t * timer ) {
2014-08-15 21:26:50 +00:00
log_info ( " SM timeout " ) ;
2015-02-12 15:27:54 +00:00
sm_connection_t * sm_conn = ( sm_connection_t * ) linked_item_get_user ( ( linked_item_t * ) timer ) ;
sm_conn - > sm_engine_state = SM_GENERAL_TIMEOUT ;
2015-02-27 14:17:45 +00:00
sm_done_for_handle ( sm_conn - > sm_handle ) ;
2015-02-27 10:52:33 +00:00
// trigger handling of next ready connection
sm_run ( ) ;
2014-01-05 19:21:33 +00:00
}
2015-02-27 14:17:45 +00:00
static void sm_timeout_start ( sm_connection_t * sm_conn ) {
run_loop_remove_timer ( & setup - > sm_timeout ) ;
run_loop_set_timer_handler ( & setup - > sm_timeout , sm_timeout_handler ) ;
run_loop_set_timer ( & setup - > sm_timeout , 30000 ) ; // 30 seconds sm timeout
linked_item_set_user ( ( linked_item_t * ) & setup - > sm_timeout , sm_conn ) ;
run_loop_add_timer ( & setup - > sm_timeout ) ;
2014-01-05 19:21:33 +00:00
}
2015-05-13 10:30:46 +02:00
static void sm_timeout_stop ( void ) {
2015-02-27 14:17:45 +00:00
run_loop_remove_timer ( & setup - > sm_timeout ) ;
2014-01-05 19:21:33 +00:00
}
2015-02-27 14:17:45 +00:00
static void sm_timeout_reset ( sm_connection_t * sm_conn ) {
sm_timeout_stop ( ) ;
sm_timeout_start ( sm_conn ) ;
2014-01-05 19:21:33 +00:00
}
// end of sm timeout
// GAP Random Address updates
static gap_random_address_type_t gap_random_adress_type ;
static timer_source_t gap_random_address_update_timer ;
static uint32_t gap_random_adress_update_period ;
2015-05-13 10:30:46 +02:00
static void gap_random_address_trigger ( void ) {
2014-02-02 18:45:00 +00:00
if ( rau_state ! = RAU_IDLE ) return ;
2014-08-15 21:26:50 +00:00
log_info ( " gap_random_address_trigger " ) ;
2014-02-02 18:45:00 +00:00
rau_state = RAU_GET_RANDOM ;
sm_run ( ) ;
}
2014-01-05 19:21:33 +00:00
static void gap_random_address_update_handler ( timer_source_t * timer ) {
2014-08-15 21:26:50 +00:00
log_info ( " GAP Random Address Update due " ) ;
2014-01-05 19:21:33 +00:00
run_loop_set_timer ( & gap_random_address_update_timer , gap_random_adress_update_period ) ;
run_loop_add_timer ( & gap_random_address_update_timer ) ;
2014-02-02 18:45:00 +00:00
gap_random_address_trigger ( ) ;
2014-01-05 19:21:33 +00:00
}
2015-05-13 10:30:46 +02:00
static void gap_random_address_update_start ( void ) {
2014-01-05 19:21:33 +00:00
run_loop_set_timer_handler ( & gap_random_address_update_timer , gap_random_address_update_handler ) ;
run_loop_set_timer ( & gap_random_address_update_timer , gap_random_adress_update_period ) ;
run_loop_add_timer ( & gap_random_address_update_timer ) ;
}
2015-05-13 10:30:46 +02:00
static void gap_random_address_update_stop ( void ) {
2014-01-05 19:21:33 +00:00
run_loop_remove_timer ( & gap_random_address_update_timer ) ;
}
2015-02-12 16:16:42 +00:00
static void sm_random_start ( sm_connection_t * sm_conn ) {
sm_random_connection_source = sm_conn ;
hci_send_cmd ( & hci_le_rand ) ;
}
2014-06-12 13:38:17 +00:00
// pre: sm_aes128_state != SM_AES128_ACTIVE, hci_can_send_command == 1
2015-02-12 16:16:42 +00:00
// sm_conn is made availabe to aes128 result handler by this
static void sm_aes128_start ( sm_key_t key , sm_key_t plaintext , sm_connection_t * sm_conn ) {
2014-06-12 13:38:17 +00:00
sm_aes128_state = SM_AES128_ACTIVE ;
2014-01-05 19:21:33 +00:00
sm_key_t key_flipped , plaintext_flipped ;
swap128 ( key , key_flipped ) ;
swap128 ( plaintext , plaintext_flipped ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_connection_source = sm_conn ;
2014-01-05 19:21:33 +00:00
hci_send_cmd ( & hci_le_encrypt , key_flipped , plaintext_flipped ) ;
}
2014-06-15 10:26:41 +00:00
// ah(k,r) helper
// r = padding || r
// r - 24 bit value
static void sm_ah_r_prime ( uint8_t r [ 3 ] , sm_key_t r_prime ) {
2014-01-05 19:21:33 +00:00
// r'= padding || r
2014-06-15 10:26:41 +00:00
memset ( r_prime , 0 , 16 ) ;
memcpy ( & r_prime [ 13 ] , r , 3 ) ;
2014-01-05 19:21:33 +00:00
}
2014-06-15 10:26:41 +00:00
// d1 helper
// d' = padding || r || d
// d,r - 16 bit values
2014-01-05 19:21:33 +00:00
static void sm_d1_d_prime ( uint16_t d , uint16_t r , sm_key_t d1_prime ) {
// d'= padding || r || d
memset ( d1_prime , 0 , 16 ) ;
net_store_16 ( d1_prime , 12 , r ) ;
net_store_16 ( d1_prime , 14 , d ) ;
}
2014-06-15 10:26:41 +00:00
// dm helper
// r’ = padding || r
// r - 64 bit value
2014-01-05 19:21:33 +00:00
static void sm_dm_r_prime ( uint8_t r [ 8 ] , sm_key_t r_prime ) {
memset ( r_prime , 0 , 16 ) ;
memcpy ( & r_prime [ 8 ] , r , 8 ) ;
}
// calculate arguments for first AES128 operation in C1 function
static void sm_c1_t1 ( sm_key_t r , uint8_t preq [ 7 ] , uint8_t pres [ 7 ] , uint8_t iat , uint8_t rat , sm_key_t t1 ) {
// p1 = pres || preq || rat’ || iat’
// "The octet of iat’ becomes the least significant octet of p1 and the most signifi-
// cant octet of pres becomes the most significant octet of p1.
// For example, if the 8-bit iat’ is 0x01, the 8-bit rat’ is 0x00, the 56-bit preq
// is 0x07071000000101 and the 56 bit pres is 0x05000800000302 then
// p1 is 0x05000800000302070710000001010001."
sm_key_t p1 ;
swap56 ( pres , & p1 [ 0 ] ) ;
swap56 ( preq , & p1 [ 7 ] ) ;
p1 [ 14 ] = rat ;
p1 [ 15 ] = iat ;
2014-08-15 21:26:50 +00:00
log_key ( " p1 " , p1 ) ;
log_key ( " r " , r ) ;
2014-01-05 19:21:33 +00:00
// t1 = r xor p1
int i ;
for ( i = 0 ; i < 16 ; i + + ) {
t1 [ i ] = r [ i ] ^ p1 [ i ] ;
}
2014-08-15 21:26:50 +00:00
log_key ( " t1 " , t1 ) ;
2014-01-05 19:21:33 +00:00
}
// calculate arguments for second AES128 operation in C1 function
static void sm_c1_t3 ( sm_key_t t2 , bd_addr_t ia , bd_addr_t ra , sm_key_t t3 ) {
// p2 = padding || ia || ra
// "The least significant octet of ra becomes the least significant octet of p2 and
// the most significant octet of padding becomes the most significant octet of p2.
// For example, if 48-bit ia is 0xA1A2A3A4A5A6 and the 48-bit ra is
// 0xB1B2B3B4B5B6 then p2 is 0x00000000A1A2A3A4A5A6B1B2B3B4B5B6.
sm_key_t p2 ;
memset ( p2 , 0 , 16 ) ;
memcpy ( & p2 [ 4 ] , ia , 6 ) ;
memcpy ( & p2 [ 10 ] , ra , 6 ) ;
2014-08-15 21:26:50 +00:00
log_key ( " p2 " , p2 ) ;
2014-01-05 19:21:33 +00:00
// c1 = e(k, t2_xor_p2)
int i ;
for ( i = 0 ; i < 16 ; i + + ) {
t3 [ i ] = t2 [ i ] ^ p2 [ i ] ;
}
2014-08-15 21:26:50 +00:00
log_key ( " t3 " , t3 ) ;
2014-01-05 19:21:33 +00:00
}
static void sm_s1_r_prime ( sm_key_t r1 , sm_key_t r2 , sm_key_t r_prime ) {
2014-08-15 21:26:50 +00:00
log_key ( " r1 " , r1 ) ;
log_key ( " r2 " , r2 ) ;
2014-01-05 19:21:33 +00:00
memcpy ( & r_prime [ 8 ] , & r2 [ 8 ] , 8 ) ;
memcpy ( & r_prime [ 0 ] , & r1 [ 8 ] , 8 ) ;
}
2014-01-06 12:58:18 +00:00
static void sm_notify_client ( uint8_t type , uint8_t addr_type , bd_addr_t address , uint32_t passkey , uint16_t index ) {
sm_event_t event ;
2014-01-05 19:42:21 +00:00
event . type = type ;
2014-01-06 12:58:18 +00:00
event . addr_type = addr_type ;
BD_ADDR_COPY ( event . address , address ) ;
event . passkey = passkey ;
2015-03-02 21:44:16 +00:00
event . le_device_db_index = index ;
2014-01-05 19:42:21 +00:00
2015-03-02 21:44:16 +00:00
log_info ( " sm_notify_client %02x, addres_type %u, address %s, num '%06u', index %u " , event . type , event . addr_type , bd_addr_to_str ( event . address ) , event . passkey , event . le_device_db_index ) ;
2014-01-05 19:42:21 +00:00
if ( ! sm_client_packet_handler ) return ;
2014-01-06 12:58:18 +00:00
sm_client_packet_handler ( HCI_EVENT_PACKET , 0 , ( uint8_t * ) & event , sizeof ( event ) ) ;
2014-01-05 19:42:21 +00:00
}
2014-01-06 12:58:18 +00:00
static void sm_notify_client_authorization ( uint8_t type , uint8_t addr_type , bd_addr_t address , uint8_t result ) {
2014-01-05 19:21:33 +00:00
2014-01-06 12:58:18 +00:00
sm_event_t event ;
2014-01-05 19:21:33 +00:00
event . type = type ;
event . addr_type = addr_type ;
BD_ADDR_COPY ( event . address , address ) ;
2014-01-06 12:58:18 +00:00
event . authorization_result = result ;
2014-01-05 19:21:33 +00:00
2014-01-07 18:24:50 +00:00
log_info ( " sm_notify_client_authorization %02x, address_type %u, address %s, result %u " , event . type , event . addr_type , bd_addr_to_str ( event . address ) , event . authorization_result ) ;
2014-01-05 19:21:33 +00:00
if ( ! sm_client_packet_handler ) return ;
2014-01-06 12:58:18 +00:00
sm_client_packet_handler ( HCI_EVENT_PACKET , 0 , ( uint8_t * ) & event , sizeof ( event ) ) ;
2014-01-05 19:21:33 +00:00
}
// decide on stk generation based on
// - pairing request
// - io capabilities
// - OOB data availability
2015-05-13 10:30:46 +02:00
static void sm_setup_tk ( void ) {
2014-01-05 19:21:33 +00:00
// default: just works
2014-06-13 10:19:18 +00:00
setup - > sm_stk_generation_method = JUST_WORKS ;
2014-04-11 13:07:27 +00:00
2014-01-05 19:21:33 +00:00
// If both devices have out of band authentication data, then the Authentication
// Requirements Flags shall be ignored when selecting the pairing method and the
// Out of Band pairing method shall be used.
2014-06-12 23:30:07 +00:00
if ( setup - > sm_m_preq . oob_data_flag & & setup - > sm_s_pres . oob_data_flag ) {
2014-08-15 21:26:50 +00:00
log_info ( " SM: have OOB data " ) ;
log_key ( " OOB " , setup - > sm_tk ) ;
2014-06-13 10:19:18 +00:00
setup - > sm_stk_generation_method = OOB ;
2014-01-05 19:21:33 +00:00
return ;
}
// If both devices have not set the MITM option in the Authentication Requirements
// Flags, then the IO capabilities shall be ignored and the Just Works association
// model shall be used.
2014-06-12 23:30:07 +00:00
if ( ( ( setup - > sm_m_preq . auth_req & SM_AUTHREQ_MITM_PROTECTION ) = = 0x00 ) & & ( ( setup - > sm_s_pres . auth_req & SM_AUTHREQ_MITM_PROTECTION ) = = 0 ) ) {
2014-01-05 19:21:33 +00:00
return ;
}
// Also use just works if unknown io capabilites
2014-06-12 23:30:07 +00:00
if ( ( setup - > sm_m_preq . io_capability > IO_CAPABILITY_KEYBOARD_DISPLAY ) | | ( setup - > sm_m_preq . io_capability > IO_CAPABILITY_KEYBOARD_DISPLAY ) ) {
2014-01-05 19:21:33 +00:00
return ;
}
// Otherwise the IO capabilities of the devices shall be used to determine the
// pairing method as defined in Table 2.4.
2014-06-13 10:19:18 +00:00
setup - > sm_stk_generation_method = stk_generation_method [ setup - > sm_s_pres . io_capability ] [ setup - > sm_m_preq . io_capability ] ;
2014-08-15 21:26:50 +00:00
log_info ( " sm_setup_tk: master io cap: %u, slave io cap: %u -> method %u " ,
2014-06-13 10:19:18 +00:00
setup - > sm_m_preq . io_capability , setup - > sm_s_pres . io_capability , setup - > sm_stk_generation_method ) ;
2014-01-05 19:21:33 +00:00
}
static int sm_key_distribution_flags_for_set ( uint8_t key_set ) {
int flags = 0 ;
if ( key_set & SM_KEYDIST_ENC_KEY ) {
flags | = SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION ;
flags | = SM_KEYDIST_FLAG_MASTER_IDENTIFICATION ;
}
if ( key_set & SM_KEYDIST_ID_KEY ) {
flags | = SM_KEYDIST_FLAG_IDENTITY_INFORMATION ;
flags | = SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION ;
}
if ( key_set & SM_KEYDIST_SIGN ) {
flags | = SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION ;
}
return flags ;
}
static void sm_setup_key_distribution ( uint8_t key_set ) {
2014-06-12 21:16:47 +00:00
setup - > sm_key_distribution_received_set = 0 ;
setup - > sm_key_distribution_send_set = sm_key_distribution_flags_for_set ( key_set ) ;
2014-01-05 19:21:33 +00:00
}
2014-06-12 15:07:01 +00:00
// CSRK Key Lookup
2015-05-13 10:30:46 +02:00
/* static */ int sm_central_device_lookup_active ( void ) {
2014-06-12 15:07:01 +00:00
return sm_central_device_test > = 0 ;
}
2015-02-12 21:36:06 +00:00
static void sm_central_device_start_lookup ( sm_connection_t * sm_conn , uint8_t addr_type , bd_addr_t addr ) {
2014-06-12 15:07:01 +00:00
memcpy ( sm_central_device_address , addr , 6 ) ;
sm_central_device_addr_type = addr_type ;
sm_central_device_test = 0 ;
sm_central_device_matched = - 1 ;
2015-02-12 21:36:06 +00:00
sm_csrk_connection_source = sm_conn ;
2014-06-12 15:07:01 +00:00
sm_notify_client ( SM_IDENTITY_RESOLVING_STARTED , addr_type , addr , 0 , 0 ) ;
}
2014-01-05 19:21:33 +00:00
// CMAC Implementation using AES128 engine
static void sm_shift_left_by_one_bit_inplace ( int len , uint8_t * data ) {
int i ;
int carry = 0 ;
for ( i = len - 1 ; i > = 0 ; i - - ) {
int new_carry = data [ i ] > > 7 ;
data [ i ] = data [ i ] < < 1 | carry ;
carry = new_carry ;
}
}
2014-06-12 10:12:23 +00:00
// while x_state++ for an enum is possible in C, it isn't in C++. we use this helpers to avoid compile errors for now
2015-02-12 15:37:01 +00:00
static inline void sm_next_responding_state ( sm_connection_t * sm_conn ) {
sm_conn - > sm_engine_state = ( security_manager_state_t ) ( ( ( int ) sm_conn - > sm_engine_state ) + 1 ) ;
2014-06-12 10:12:23 +00:00
}
2015-05-13 10:30:46 +02:00
static inline void dkg_next_state ( void ) {
2014-06-12 10:12:23 +00:00
dkg_state = ( derived_key_generation_t ) ( ( ( int ) dkg_state ) + 1 ) ;
}
2015-05-13 10:30:46 +02:00
static inline void rau_next_state ( void ) {
2014-06-12 10:12:23 +00:00
rau_state = ( random_address_update_t ) ( ( ( int ) rau_state ) + 1 ) ;
}
2015-05-13 10:30:46 +02:00
static inline void sm_cmac_next_state ( void ) {
2014-06-12 10:12:23 +00:00
sm_cmac_state = ( cmac_state_t ) ( ( ( int ) sm_cmac_state ) + 1 ) ;
}
2015-05-13 10:30:46 +02:00
static int sm_cmac_last_block_complete ( void ) {
2014-01-05 19:21:33 +00:00
if ( sm_cmac_message_len = = 0 ) return 0 ;
return ( sm_cmac_message_len & 0x0f ) = = 0 ;
}
2015-03-05 14:42:26 +00:00
static inline uint8_t sm_cmac_message_get_byte ( int 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 ;
}
int actual_len = sm_cmac_message_len - 4 ;
if ( offset < actual_len ) {
return sm_cmac_message [ offset ] ;
} else {
return sm_cmac_message [ offset - actual_len ] ;
}
}
2014-01-05 19:21:33 +00:00
2015-03-05 14:42:26 +00:00
void sm_cmac_start ( sm_key_t k , uint16_t message_len , uint8_t * message , uint32_t sign_counter , void ( * done_handler ) ( uint8_t hash [ 8 ] ) ) {
2014-01-05 19:21:33 +00:00
memcpy ( sm_cmac_k , k , 16 ) ;
2015-03-05 14:42:26 +00:00
sm_cmac_message_len = message_len + 4 ; // incl. virtually appended sign_counter in LE
2014-01-05 19:21:33 +00:00
sm_cmac_message = message ;
2015-03-05 14:42:26 +00:00
bt_store_32 ( sm_cmac_sign_counter , 0 , sign_counter ) ;
2014-01-05 19:21:33 +00:00
sm_cmac_done_handler = done_handler ;
sm_cmac_block_current = 0 ;
memset ( sm_cmac_x , 0 , 16 ) ;
// step 2: n := ceil(len/const_Bsize);
2015-03-05 14:42:26 +00:00
sm_cmac_block_count = ( sm_cmac_message_len + 15 ) / 16 ;
2014-01-05 19:21:33 +00:00
// step 3: ..
if ( sm_cmac_block_count = = 0 ) {
sm_cmac_block_count = 1 ;
}
// first, we need to compute l for k1, k2, and m_last
sm_cmac_state = CMAC_CALC_SUBKEYS ;
// let's go
sm_run ( ) ;
}
2015-05-13 10:30:46 +02:00
int sm_cmac_ready ( void ) {
2014-01-05 19:21:33 +00:00
return sm_cmac_state = = CMAC_IDLE ;
}
2015-05-13 10:30:46 +02:00
static void sm_cmac_handle_aes_engine_ready ( void ) {
2014-01-05 19:21:33 +00:00
switch ( sm_cmac_state ) {
2014-10-16 15:02:48 +00:00
case CMAC_CALC_SUBKEYS : {
2014-01-05 19:21:33 +00:00
sm_key_t const_zero ;
memset ( const_zero , 0 , 16 ) ;
2014-06-12 10:12:23 +00:00
sm_cmac_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_start ( sm_cmac_k , const_zero , NULL ) ;
2014-01-05 19:21:33 +00:00
break ;
2014-10-16 15:02:48 +00:00
}
2014-01-05 19:21:33 +00:00
case CMAC_CALC_MI : {
int j ;
sm_key_t y ;
for ( j = 0 ; j < 16 ; j + + ) {
2015-03-05 14:42:26 +00:00
y [ j ] = sm_cmac_x [ j ] ^ sm_cmac_message_get_byte ( sm_cmac_block_current * 16 + j ) ;
2014-01-05 19:21:33 +00:00
}
sm_cmac_block_current + + ;
2014-06-12 10:12:23 +00:00
sm_cmac_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_start ( sm_cmac_k , y , NULL ) ;
2014-01-05 19:21:33 +00:00
break ;
}
case CMAC_CALC_MLAST : {
int i ;
sm_key_t y ;
for ( i = 0 ; i < 16 ; i + + ) {
y [ i ] = sm_cmac_x [ i ] ^ sm_cmac_m_last [ i ] ;
}
2014-08-15 21:26:50 +00:00
log_key ( " Y " , y ) ;
2014-01-05 19:21:33 +00:00
sm_cmac_block_current + + ;
2014-06-12 10:12:23 +00:00
sm_cmac_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_start ( sm_cmac_k , y , NULL ) ;
2014-01-05 19:21:33 +00:00
break ;
}
default :
2014-08-15 21:26:50 +00:00
log_info ( " sm_cmac_handle_aes_engine_ready called in state %u " , sm_cmac_state ) ;
2014-01-05 19:21:33 +00:00
break ;
}
}
static void sm_cmac_handle_encryption_result ( sm_key_t data ) {
switch ( sm_cmac_state ) {
case CMAC_W4_SUBKEYS : {
sm_key_t k1 ;
memcpy ( k1 , data , 16 ) ;
sm_shift_left_by_one_bit_inplace ( 16 , k1 ) ;
if ( data [ 0 ] & 0x80 ) {
k1 [ 15 ] ^ = 0x87 ;
}
sm_key_t k2 ;
memcpy ( k2 , k1 , 16 ) ;
sm_shift_left_by_one_bit_inplace ( 16 , k2 ) ;
if ( k1 [ 0 ] & 0x80 ) {
k2 [ 15 ] ^ = 0x87 ;
}
2014-08-15 21:26:50 +00:00
log_key ( " k " , sm_cmac_k ) ;
log_key ( " k1 " , k1 ) ;
log_key ( " k2 " , k2 ) ;
2014-01-05 19:21:33 +00:00
// step 4: set m_last
2014-01-05 22:40:51 +00:00
int i ;
2014-01-05 19:21:33 +00:00
if ( sm_cmac_last_block_complete ( ) ) {
for ( i = 0 ; i < 16 ; i + + ) {
2015-03-05 14:42:26 +00:00
sm_cmac_m_last [ i ] = sm_cmac_message_get_byte ( sm_cmac_message_len - 16 + i ) ^ k1 [ i ] ;
2014-01-05 19:21:33 +00:00
}
} else {
int valid_octets_in_last_block = sm_cmac_message_len & 0x0f ;
for ( i = 0 ; i < 16 ; i + + ) {
if ( i < valid_octets_in_last_block ) {
2015-03-05 14:42:26 +00:00
sm_cmac_m_last [ i ] = sm_cmac_message_get_byte ( ( sm_cmac_message_len & 0xfff0 ) + i ) ^ k2 [ i ] ;
2014-01-05 19:21:33 +00:00
continue ;
}
if ( i = = valid_octets_in_last_block ) {
sm_cmac_m_last [ i ] = 0x80 ^ k2 [ i ] ;
continue ;
}
sm_cmac_m_last [ i ] = k2 [ i ] ;
}
}
// next
sm_cmac_state = sm_cmac_block_current < sm_cmac_block_count - 1 ? CMAC_CALC_MI : CMAC_CALC_MLAST ;
break ;
}
case CMAC_W4_MI :
memcpy ( sm_cmac_x , data , 16 ) ;
sm_cmac_state = sm_cmac_block_current < sm_cmac_block_count - 1 ? CMAC_CALC_MI : CMAC_CALC_MLAST ;
break ;
2014-02-02 18:45:00 +00:00
case CMAC_W4_MLAST :
2014-01-05 19:21:33 +00:00
// done
2014-08-15 21:26:50 +00:00
log_key ( " CMAC " , data ) ;
2014-02-02 18:45:00 +00:00
sm_cmac_done_handler ( data ) ;
2014-01-05 19:21:33 +00:00
break ;
default :
2014-08-15 21:26:50 +00:00
log_info ( " sm_cmac_handle_encryption_result called in state %u " , sm_cmac_state ) ;
2014-01-05 19:21:33 +00:00
break ;
}
}
2015-02-12 15:37:01 +00:00
static void sm_trigger_user_response ( sm_connection_t * sm_conn ) {
2014-06-15 15:43:05 +00:00
// notify client for: JUST WORKS confirm, PASSKEY display or input
setup - > sm_user_response = SM_USER_RESPONSE_IDLE ;
switch ( setup - > sm_stk_generation_method ) {
case PK_RESP_INPUT :
2015-02-12 15:37:01 +00:00
if ( sm_conn - > sm_role ) {
2014-06-15 15:43:05 +00:00
setup - > sm_user_response = SM_USER_RESPONSE_PENDING ;
sm_notify_client ( SM_PASSKEY_INPUT_NUMBER , setup - > sm_m_addr_type , setup - > sm_m_address , 0 , 0 ) ;
} else {
sm_notify_client ( SM_PASSKEY_DISPLAY_NUMBER , setup - > sm_m_addr_type , setup - > sm_m_address , READ_NET_32 ( setup - > sm_tk , 12 ) , 0 ) ;
}
break ;
case PK_INIT_INPUT :
2015-02-12 15:37:01 +00:00
if ( sm_conn - > sm_role ) {
2014-06-15 15:43:05 +00:00
sm_notify_client ( SM_PASSKEY_DISPLAY_NUMBER , setup - > sm_m_addr_type , setup - > sm_m_address , READ_NET_32 ( setup - > sm_tk , 12 ) , 0 ) ;
} else {
setup - > sm_user_response = SM_USER_RESPONSE_PENDING ;
sm_notify_client ( SM_PASSKEY_INPUT_NUMBER , setup - > sm_m_addr_type , setup - > sm_m_address , 0 , 0 ) ;
}
break ;
case JUST_WORKS :
switch ( setup - > sm_s_pres . io_capability ) {
case IO_CAPABILITY_KEYBOARD_DISPLAY :
case IO_CAPABILITY_DISPLAY_YES_NO :
setup - > sm_user_response = SM_USER_RESPONSE_PENDING ;
sm_notify_client ( SM_JUST_WORKS_REQUEST , setup - > sm_m_addr_type , setup - > sm_m_address , READ_NET_32 ( setup - > sm_tk , 12 ) , 0 ) ;
break ;
default :
// cannot ask user
break ;
}
break ;
default :
break ;
}
}
2015-05-13 10:30:46 +02:00
static int sm_key_distribution_all_received ( void ) {
2014-06-12 23:30:07 +00:00
int recv_flags = sm_key_distribution_flags_for_set ( setup - > sm_m_preq . initiator_key_distribution ) ;
2014-06-12 21:16:47 +00:00
return recv_flags = = setup - > sm_key_distribution_received_set ;
2014-01-05 19:21:33 +00:00
}
2015-02-27 10:52:33 +00:00
static void sm_done_for_handle ( uint16_t handle ) {
if ( sm_active_connection = = handle ) {
2015-02-27 14:17:45 +00:00
sm_timeout_stop ( ) ;
2015-02-27 10:52:33 +00:00
sm_active_connection = 0 ;
2015-02-27 14:17:45 +00:00
log_info ( " sm: connection 0x%x released setup context " , handle ) ;
2015-02-27 10:52:33 +00:00
}
2014-01-05 19:21:33 +00:00
}
2015-02-27 10:52:33 +00:00
static void sm_init_setup ( sm_connection_t * sm_conn ) {
2014-06-12 15:07:01 +00:00
2015-02-27 10:52:33 +00:00
// fill in sm setup
sm_reset_tk ( ) ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
// query client for OOB data
int have_oob_data = 0 ;
if ( sm_get_oob_data ) {
2015-03-01 20:51:08 +00:00
have_oob_data = ( * sm_get_oob_data ) ( sm_conn - > sm_peer_addr_type , sm_conn - > sm_peer_address , setup - > sm_tk ) ;
2015-02-27 10:52:33 +00:00
}
2015-02-27 19:56:00 +00:00
sm_pairing_packet_t * local_packet ;
2015-02-27 10:52:33 +00:00
if ( sm_conn - > sm_role ) {
// slave
2015-02-27 19:56:00 +00:00
local_packet = & setup - > sm_s_pres ;
2015-03-01 20:51:08 +00:00
hci_le_advertisement_address ( & setup - > sm_s_addr_type , setup - > sm_s_address ) ;
2015-02-27 10:52:33 +00:00
setup - > sm_m_addr_type = sm_conn - > sm_peer_addr_type ;
memcpy ( setup - > sm_m_address , sm_conn - > sm_peer_address , 6 ) ;
} else {
// master
2015-02-27 19:56:00 +00:00
local_packet = & setup - > sm_m_preq ;
2015-03-01 20:51:08 +00:00
hci_le_advertisement_address ( & setup - > sm_m_addr_type , setup - > sm_m_address ) ;
2015-02-27 10:52:33 +00:00
setup - > sm_s_addr_type = sm_conn - > sm_peer_addr_type ;
memcpy ( setup - > sm_s_address , sm_conn - > sm_peer_address , 6 ) ;
2015-02-27 16:53:54 +00:00
2015-02-27 10:52:33 +00:00
setup - > sm_m_preq . initiator_key_distribution = 0x07 ;
setup - > sm_m_preq . responder_key_distribution = 0x07 ;
}
2015-02-27 19:56:00 +00:00
local_packet - > io_capability = sm_io_capabilities ;
local_packet - > oob_data_flag = have_oob_data ;
local_packet - > auth_req = sm_auth_req ;
local_packet - > max_encryption_key_size = sm_max_encryption_key_size ;
2015-02-27 10:52:33 +00:00
}
2015-02-27 19:56:00 +00:00
static int sm_stk_generation_init ( sm_connection_t * sm_conn ) {
2015-02-27 16:53:54 +00:00
2015-02-27 19:56:00 +00:00
sm_pairing_packet_t * remote_packet ;
int remote_key_request ;
if ( sm_conn - > sm_role ) {
remote_packet = & setup - > sm_m_preq ;
remote_key_request = setup - > sm_m_preq . responder_key_distribution ;
} else {
remote_packet = & setup - > sm_s_pres ;
remote_key_request = setup - > sm_s_pres . initiator_key_distribution ;
}
2015-02-27 16:53:54 +00:00
// check key size
2015-02-27 19:56:00 +00:00
sm_conn - > sm_actual_encryption_key_size = sm_calc_actual_encryption_key_size ( remote_packet - > max_encryption_key_size ) ;
if ( sm_conn - > sm_actual_encryption_key_size = = 0 ) return SM_REASON_ENCRYPTION_KEY_SIZE ;
2015-02-27 16:53:54 +00:00
// setup key distribution
2015-02-27 19:56:00 +00:00
sm_setup_key_distribution ( remote_key_request ) ;
2015-02-27 16:53:54 +00:00
// identical to responder
// decide on STK generation method
sm_setup_tk ( ) ;
log_info ( " SMP: generation method %u " , setup - > sm_stk_generation_method ) ;
// check if STK generation method is acceptable by client
2015-02-27 19:56:00 +00:00
if ( ! sm_validate_stk_generation_method ( ) ) return SM_REASON_AUTHENTHICATION_REQUIREMENTS ;
2015-02-27 10:52:33 +00:00
// JUST WORKS doens't provide authentication
sm_conn - > sm_connection_authenticated = setup - > sm_stk_generation_method = = JUST_WORKS ? 0 : 1 ;
2015-02-27 19:56:00 +00:00
return 0 ;
2015-02-27 10:52:33 +00:00
}
static void sm_run ( void ) {
linked_list_iterator_t it ;
// assert that we can send at least commands
if ( ! hci_can_send_command_packet_now ( ) ) return ;
//
// non-connection related behaviour
//
2014-01-05 19:21:33 +00:00
// distributed key generation
switch ( dkg_state ) {
case DKG_CALC_IRK :
// already busy?
2014-10-16 15:02:48 +00:00
if ( sm_aes128_state = = SM_AES128_IDLE ) {
// IRK = d1(IR, 1, 0)
sm_key_t d1_prime ;
sm_d1_d_prime ( 1 , 0 , d1_prime ) ; // plaintext
dkg_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_start ( sm_persistent_ir , d1_prime , NULL ) ;
2014-10-16 15:02:48 +00:00
return ;
2014-01-05 19:21:33 +00:00
}
2014-10-16 15:02:48 +00:00
break ;
2014-01-05 19:21:33 +00:00
case DKG_CALC_DHK :
// already busy?
2014-10-16 15:02:48 +00:00
if ( sm_aes128_state = = SM_AES128_IDLE ) {
// DHK = d1(IR, 3, 0)
sm_key_t d1_prime ;
sm_d1_d_prime ( 3 , 0 , d1_prime ) ; // plaintext
dkg_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_start ( sm_persistent_ir , d1_prime , NULL ) ;
2014-10-16 15:02:48 +00:00
return ;
2014-01-05 19:21:33 +00:00
}
2014-10-16 15:02:48 +00:00
break ;
2014-01-05 19:21:33 +00:00
default :
break ;
}
// random address updates
switch ( rau_state ) {
case RAU_GET_RANDOM :
2014-06-12 10:12:23 +00:00
rau_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_random_start ( NULL ) ;
2014-01-05 19:21:33 +00:00
return ;
case RAU_GET_ENC :
// already busy?
2014-10-16 15:02:48 +00:00
if ( sm_aes128_state = = SM_AES128_IDLE ) {
sm_key_t r_prime ;
sm_ah_r_prime ( sm_random_address , r_prime ) ;
rau_next_state ( ) ;
2015-02-12 16:16:42 +00:00
sm_aes128_start ( sm_persistent_irk , r_prime , NULL ) ;
2014-10-16 15:02:48 +00:00
return ;
2014-01-05 19:21:33 +00:00
}
2014-10-16 15:02:48 +00:00
break ;
2014-01-05 19:21:33 +00:00
case RAU_SET_ADDRESS :
2014-08-15 21:26:50 +00:00
log_info ( " New random address: %s " , bd_addr_to_str ( sm_random_address ) ) ;
2014-01-05 19:21:33 +00:00
rau_state = RAU_IDLE ;
2014-10-16 15:02:48 +00:00
hci_send_cmd ( & hci_le_set_random_address , sm_random_address ) ;
2014-01-05 19:21:33 +00:00
return ;
default :
break ;
}
2015-02-27 10:52:33 +00:00
// CMAC
switch ( sm_cmac_state ) {
case CMAC_CALC_SUBKEYS :
case CMAC_CALC_MI :
case CMAC_CALC_MLAST :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
sm_cmac_handle_aes_engine_ready ( ) ;
return ;
default :
break ;
}
// CSRK Lookup
// -- if csrk lookup ready, find connection that require csrk lookup
if ( ! sm_central_device_lookup_active ( ) ) {
hci_connections_get_iterator ( & it ) ;
while ( linked_list_iterator_has_next ( & it ) ) {
hci_connection_t * hci_connection = ( hci_connection_t * ) linked_list_iterator_next ( & it ) ;
sm_connection_t * sm_connection = & hci_connection - > sm_connection ;
if ( sm_connection - > sm_csrk_lookup_state = = CSRK_LOOKUP_W4_READY ) {
// and start lookup
sm_central_device_start_lookup ( sm_connection , sm_connection - > sm_peer_addr_type , sm_connection - > sm_peer_address ) ;
sm_connection - > sm_csrk_lookup_state = CSRK_LOOKUP_STARTED ;
break ;
}
}
}
// -- Continue with CSRK device lookup by public or resolvable private address
2014-01-05 19:21:33 +00:00
if ( sm_central_device_test > = 0 ) {
2015-03-03 21:38:29 +00:00
log_info ( " LE Device Lookup: device %u/%u " , sm_central_device_test , le_device_db_count ( ) ) ;
2015-03-02 21:30:12 +00:00
while ( sm_central_device_test < le_device_db_count ( ) ) {
2014-01-05 19:21:33 +00:00
int addr_type ;
bd_addr_t addr ;
sm_key_t irk ;
2015-03-02 21:30:12 +00:00
le_device_db_info ( sm_central_device_test , & addr_type , addr , irk ) ;
2014-08-15 21:26:50 +00:00
log_info ( " device type %u, addr: %s " , addr_type , bd_addr_to_str ( addr ) ) ;
2014-01-05 19:21:33 +00:00
2014-06-12 15:07:01 +00:00
if ( sm_central_device_addr_type = = addr_type & & memcmp ( addr , sm_central_device_address , 6 ) = = 0 ) {
2015-03-03 21:38:29 +00:00
log_info ( " LE Device Lookup: found CSRK by { addr_type, address} " ) ;
2014-01-05 19:21:33 +00:00
sm_central_device_matched = sm_central_device_test ;
sm_central_device_test = - 1 ;
2015-03-03 21:38:29 +00:00
sm_notify_client ( SM_IDENTITY_RESOLVING_SUCCEEDED , sm_central_device_addr_type , sm_central_device_address , 0 , sm_central_device_matched ) ;
// re-use stored LTK/EDIV/RAND if requested & we're master
// TODO: replace global with flag in sm_connection_t
if ( sm_authenticate_outgoing_connections & & sm_csrk_connection_source - > sm_role = = 0 ) {
sm_csrk_connection_source - > sm_engine_state = SM_INITIATOR_PH0_HAS_LTK ;
log_info ( " sm: Setting up previous ltk/ediv/rand " ) ;
}
// ready for other requests
2015-02-12 21:36:06 +00:00
sm_csrk_connection_source - > sm_csrk_lookup_state = CSRK_LOOKUP_IDLE ;
sm_csrk_connection_source = NULL ;
2014-01-05 19:21:33 +00:00
break ;
}
2014-06-14 21:11:34 +00:00
if ( sm_central_device_addr_type = = 0 ) {
2014-01-05 19:21:33 +00:00
sm_central_device_test + + ;
continue ;
}
2014-06-12 13:38:17 +00:00
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
2014-01-05 19:21:33 +00:00
2015-03-03 21:38:29 +00:00
log_info ( " LE Device Lookup: calculate AH " ) ;
2014-08-15 21:26:50 +00:00
log_key ( " IRK " , irk ) ;
2014-01-05 19:21:33 +00:00
sm_key_t r_prime ;
2014-06-12 15:07:01 +00:00
sm_ah_r_prime ( sm_central_device_address , r_prime ) ;
2014-01-05 19:21:33 +00:00
sm_central_ah_calculation_active = 1 ;
2015-02-12 21:36:06 +00:00
sm_aes128_start ( irk , r_prime , sm_csrk_connection_source ) ;
2014-01-05 19:21:33 +00:00
return ;
}
2015-03-02 21:30:12 +00:00
if ( sm_central_device_test > = le_device_db_count ( ) ) {
2015-03-03 21:38:29 +00:00
log_info ( " LE Device Lookup: not found " ) ;
2014-01-05 19:21:33 +00:00
sm_central_device_test = - 1 ;
2015-02-12 21:36:06 +00:00
sm_csrk_connection_source - > sm_csrk_lookup_state = CSRK_LOOKUP_IDLE ;
sm_csrk_connection_source = NULL ;
2014-06-12 15:07:01 +00:00
sm_notify_client ( SM_IDENTITY_RESOLVING_FAILED , sm_central_device_addr_type , sm_central_device_address , 0 , 0 ) ;
2014-01-05 19:21:33 +00:00
}
}
2015-02-27 10:52:33 +00:00
//
// active connection handling
// -- use loop to handle next connection if lock on setup context is released
2014-08-27 12:52:20 +00:00
2015-02-27 10:52:33 +00:00
while ( 1 ) {
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
// Find connections that requires setup context and make active if no other is locked
hci_connections_get_iterator ( & it ) ;
while ( ! sm_active_connection & & linked_list_iterator_has_next ( & it ) ) {
hci_connection_t * hci_connection = ( hci_connection_t * ) linked_list_iterator_next ( & it ) ;
sm_connection_t * sm_connection = & hci_connection - > sm_connection ;
// - if no connection locked and we're ready/waiting for setup context, fetch it and start
2015-02-27 15:53:53 +00:00
int done = 1 ;
2015-02-27 19:56:00 +00:00
int err ;
2015-02-27 10:52:33 +00:00
switch ( sm_connection - > sm_engine_state ) {
2015-04-24 12:12:37 +02:00
case SM_RESPONDER_SEND_SECURITY_REQUEST :
// send packet if possible,
if ( l2cap_can_send_fixed_channel_packet_now ( sm_connection - > sm_handle ) ) {
uint8_t buffer [ 2 ] ;
buffer [ 0 ] = SM_CODE_SECURITY_REQUEST ;
buffer [ 1 ] = SM_AUTHREQ_BONDING ;
sm_connection - > sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_REQUEST ;
l2cap_send_connectionless ( sm_connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
}
// don't lock setup context yet
done = 0 ;
break ;
2015-02-27 10:52:33 +00:00
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED :
2015-02-27 19:56:00 +00:00
sm_init_setup ( sm_connection ) ;
// recover pairing request
memcpy ( & setup - > sm_m_preq , & sm_connection - > sm_m_preq , sizeof ( sm_pairing_packet_t ) ) ;
err = sm_stk_generation_init ( sm_connection ) ;
if ( err ) {
setup - > sm_pairing_failed_reason = err ;
sm_connection - > sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED ;
break ;
}
2015-02-27 19:14:15 +00:00
sm_timeout_start ( sm_connection ) ;
2015-02-27 19:56:00 +00:00
// generate random number first, if we need to show passkey
if ( setup - > sm_stk_generation_method = = PK_INIT_INPUT ) {
sm_connection - > sm_engine_state = SM_PH2_GET_RANDOM_TK ;
break ;
}
sm_connection - > sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE ;
2015-02-27 15:53:53 +00:00
break ;
2015-03-03 21:38:29 +00:00
case SM_INITIATOR_PH0_HAS_LTK :
// fetch data from device db
2015-03-03 22:17:47 +00:00
le_device_db_encryption_get ( sm_connection - > sm_le_db_index , & setup - > sm_peer_ediv , setup - > sm_peer_rand , setup - > sm_peer_ltk ) ;
sm_connection - > sm_engine_state = SM_INITIATOR_PH0_SEND_START_ENCRYPTION ;
2015-03-03 21:38:29 +00:00
break ;
case SM_RESPONDER_PH0_RECEIVED_LTK :
2015-02-27 15:53:53 +00:00
// 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_PH4_Y_GET_ENC ;
2015-02-27 10:52:33 +00:00
break ;
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST :
2015-02-27 19:56:00 +00:00
sm_init_setup ( sm_connection ) ;
2015-02-27 19:14:15 +00:00
sm_timeout_start ( sm_connection ) ;
2015-02-27 19:56:00 +00:00
sm_connection - > sm_engine_state = SM_INITIATOR_PH1_SEND_PAIRING_REQUEST ;
2015-02-27 10:52:33 +00:00
break ;
default :
2015-02-27 15:53:53 +00:00
done = 0 ;
2015-02-27 10:52:33 +00:00
break ;
}
if ( done ) {
sm_active_connection = sm_connection - > sm_handle ;
log_info ( " sm: connection 0x%04x locked setup context as %s " , sm_active_connection , sm_connection - > sm_role ? " responder " : " initiator " ) ;
}
2014-01-05 19:21:33 +00:00
}
2015-02-27 10:52:33 +00:00
//
// active connection handling
//
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
if ( sm_active_connection = = 0 ) return ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
// assert that we could send a SM PDU - not needed for all of the following
if ( ! l2cap_can_send_fixed_channel_packet_now ( sm_active_connection ) ) return ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
sm_connection_t * connection = sm_get_connection_for_handle ( sm_active_connection ) ;
if ( ! connection ) return ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
sm_key_t plaintext ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
// responding state
switch ( connection - > sm_engine_state ) {
2014-01-05 19:21:33 +00:00
2015-04-24 12:12:37 +02:00
// general
case SM_GENERAL_SEND_PAIRING_FAILED : {
uint8_t buffer [ 2 ] ;
buffer [ 0 ] = SM_CODE_PAIRING_FAILED ;
buffer [ 1 ] = setup - > sm_pairing_failed_reason ;
connection - > sm_engine_state = SM_GENERAL_IDLE ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
sm_done_for_handle ( connection - > sm_handle ) ;
break ;
}
2015-02-27 10:52:33 +00:00
// initiator side
2015-03-03 22:17:47 +00:00
case SM_INITIATOR_PH0_SEND_START_ENCRYPTION : {
sm_key_t peer_ltk_flipped ;
swap128 ( setup - > sm_peer_ltk , peer_ltk_flipped ) ;
connection - > sm_engine_state = SM_INITIATOR_PH0_W4_CONNECTION_ENCRYPTED ;
hci_send_cmd ( & hci_le_start_encryption , connection - > sm_handle , setup - > sm_peer_rand , setup - > sm_peer_ediv , peer_ltk_flipped ) ;
return ;
}
2015-02-27 10:52:33 +00:00
case SM_INITIATOR_PH1_SEND_PAIRING_REQUEST :
setup - > sm_m_preq . code = SM_CODE_PAIRING_REQUEST ;
connection - > sm_engine_state = SM_INITIATOR_PH1_W4_PAIRING_RESPONSE ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) & setup - > sm_m_preq , sizeof ( sm_pairing_packet_t ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
break ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
// responder side
2015-03-03 21:38:29 +00:00
case SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY :
connection - > sm_engine_state = SM_GENERAL_IDLE ;
hci_send_cmd ( & hci_le_long_term_key_negative_reply , connection - > sm_handle ) ;
return ;
2014-06-12 12:57:24 +00:00
2015-03-03 21:38:29 +00:00
case SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE :
2015-02-27 10:52:33 +00:00
// echo initiator for now
setup - > sm_s_pres . code = SM_CODE_PAIRING_RESPONSE ;
setup - > sm_s_pres . initiator_key_distribution = setup - > sm_m_preq . initiator_key_distribution ;
setup - > sm_s_pres . responder_key_distribution = setup - > sm_m_preq . responder_key_distribution ;
connection - > sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_CONFIRM ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) & setup - > sm_s_pres , sizeof ( sm_pairing_packet_t ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
sm_trigger_user_response ( connection ) ;
2014-10-16 15:02:48 +00:00
return ;
2014-06-15 10:26:41 +00:00
2015-02-27 10:52:33 +00:00
case SM_PH2_SEND_PAIRING_RANDOM : {
2014-01-05 19:21:33 +00:00
uint8_t buffer [ 17 ] ;
2015-02-27 10:52:33 +00:00
buffer [ 0 ] = SM_CODE_PAIRING_RANDOM ;
swap128 ( setup - > sm_local_random , & buffer [ 1 ] ) ;
if ( connection - > sm_role ) {
connection - > sm_engine_state = SM_RESPONDER_PH2_W4_LTK_REQUEST ;
} else {
connection - > sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_RANDOM ;
}
2014-06-12 21:54:00 +00:00
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
break ;
2014-01-05 19:21:33 +00:00
}
2015-02-27 10:52:33 +00:00
case SM_PH2_GET_RANDOM_TK :
case SM_PH2_C1_GET_RANDOM_A :
case SM_PH2_C1_GET_RANDOM_B :
case SM_PH3_GET_RANDOM :
case SM_PH3_GET_DIV :
sm_next_responding_state ( connection ) ;
sm_random_start ( connection ) ;
2014-01-05 19:21:33 +00:00
return ;
2015-02-27 10:52:33 +00:00
case SM_PH2_C1_GET_ENC_B :
case SM_PH2_C1_GET_ENC_D :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( setup - > sm_tk , setup - > sm_c1_t3_value , connection ) ;
return ;
case SM_PH3_LTK_GET_ENC :
case SM_PH4_LTK_GET_ENC :
// already busy?
if ( sm_aes128_state = = SM_AES128_IDLE ) {
sm_key_t d_prime ;
sm_d1_d_prime ( setup - > sm_local_div , 0 , d_prime ) ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( sm_persistent_er , d_prime , connection ) ;
return ;
}
break ;
case SM_PH3_CSRK_GET_ENC :
// already busy?
if ( sm_aes128_state = = SM_AES128_IDLE ) {
sm_key_t d_prime ;
sm_d1_d_prime ( setup - > sm_local_div , 1 , d_prime ) ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( sm_persistent_er , d_prime , connection ) ;
return ;
}
break ;
case SM_PH2_C1_GET_ENC_C :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
// calculate m_confirm using aes128 engine - step 1
sm_c1_t1 ( setup - > sm_peer_random , ( uint8_t * ) & setup - > sm_m_preq , ( uint8_t * ) & setup - > sm_s_pres , setup - > sm_m_addr_type , setup - > sm_s_addr_type , plaintext ) ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( setup - > sm_tk , plaintext , connection ) ;
break ;
case SM_PH2_C1_GET_ENC_A :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
// calculate confirm using aes128 engine - step 1
sm_c1_t1 ( setup - > sm_local_random , ( uint8_t * ) & setup - > sm_m_preq , ( uint8_t * ) & setup - > sm_s_pres , setup - > sm_m_addr_type , setup - > sm_s_addr_type , plaintext ) ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( setup - > sm_tk , plaintext , connection ) ;
break ;
case SM_PH2_CALC_STK :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
// calculate STK
if ( connection - > sm_role ) {
sm_s1_r_prime ( setup - > sm_local_random , setup - > sm_peer_random , plaintext ) ;
} else {
sm_s1_r_prime ( setup - > sm_peer_random , setup - > sm_local_random , plaintext ) ;
}
sm_next_responding_state ( connection ) ;
sm_aes128_start ( setup - > sm_tk , plaintext , connection ) ;
break ;
case SM_PH3_Y_GET_ENC :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
// PH3B2 - calculate Y from - enc
// Y = dm(DHK, Rand)
sm_dm_r_prime ( setup - > sm_local_rand , plaintext ) ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( sm_persistent_dhk , plaintext , connection ) ;
return ;
case SM_PH2_C1_SEND_PAIRING_CONFIRM : {
2014-01-05 19:21:33 +00:00
uint8_t buffer [ 17 ] ;
2015-02-27 10:52:33 +00:00
buffer [ 0 ] = SM_CODE_PAIRING_CONFIRM ;
swap128 ( setup - > sm_local_confirm , & buffer [ 1 ] ) ;
if ( connection - > sm_role ) {
connection - > sm_engine_state = SM_RESPONDER_PH2_W4_PAIRING_RANDOM ;
} else {
connection - > sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_CONFIRM ;
}
2014-06-12 21:54:00 +00:00
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2014-01-05 19:21:33 +00:00
return ;
}
2015-02-27 10:52:33 +00:00
case SM_RESPONDER_PH2_SEND_LTK_REPLY : {
sm_key_t stk_flipped ;
swap128 ( setup - > sm_ltk , stk_flipped ) ;
connection - > sm_engine_state = SM_PH2_W4_CONNECTION_ENCRYPTED ;
hci_send_cmd ( & hci_le_long_term_key_request_reply , connection - > sm_handle , stk_flipped ) ;
2014-01-05 19:21:33 +00:00
return ;
}
2015-02-27 10:52:33 +00:00
case SM_INITIATOR_PH3_SEND_START_ENCRYPTION : {
sm_key_t stk_flipped ;
swap128 ( setup - > sm_ltk , stk_flipped ) ;
connection - > sm_engine_state = SM_PH2_W4_CONNECTION_ENCRYPTED ;
hci_send_cmd ( & hci_le_start_encryption , connection - > sm_handle , 0 , 0 , 0 , stk_flipped ) ;
2014-01-05 19:21:33 +00:00
return ;
}
2015-02-27 10:52:33 +00:00
case SM_PH4_SEND_LTK : {
sm_key_t ltk_flipped ;
swap128 ( setup - > sm_ltk , ltk_flipped ) ;
connection - > sm_engine_state = SM_GENERAL_IDLE ;
hci_send_cmd ( & hci_le_long_term_key_request_reply , connection - > sm_handle , ltk_flipped ) ;
return ;
2014-01-05 19:21:33 +00:00
}
2015-02-27 10:52:33 +00:00
case SM_PH4_Y_GET_ENC :
// already busy?
if ( sm_aes128_state = = SM_AES128_ACTIVE ) break ;
log_info ( " LTK Request: recalculating with ediv 0x%04x " , setup - > sm_local_ediv ) ;
// Y = dm(DHK, Rand)
sm_dm_r_prime ( setup - > sm_local_rand , plaintext ) ;
sm_next_responding_state ( connection ) ;
sm_aes128_start ( sm_persistent_dhk , plaintext , connection ) ;
return ;
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
case SM_PH3_DISTRIBUTE_KEYS :
if ( setup - > sm_key_distribution_send_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION ) {
setup - > sm_key_distribution_send_set & = ~ SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION ;
uint8_t buffer [ 17 ] ;
buffer [ 0 ] = SM_CODE_ENCRYPTION_INFORMATION ;
swap128 ( setup - > sm_ltk , & buffer [ 1 ] ) ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
return ;
}
if ( setup - > sm_key_distribution_send_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION ) {
setup - > sm_key_distribution_send_set & = ~ SM_KEYDIST_FLAG_MASTER_IDENTIFICATION ;
uint8_t buffer [ 11 ] ;
buffer [ 0 ] = SM_CODE_MASTER_IDENTIFICATION ;
bt_store_16 ( buffer , 1 , setup - > sm_local_ediv ) ;
swap64 ( setup - > sm_local_rand , & buffer [ 3 ] ) ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
return ;
}
if ( setup - > sm_key_distribution_send_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION ) {
setup - > sm_key_distribution_send_set & = ~ SM_KEYDIST_FLAG_IDENTITY_INFORMATION ;
uint8_t buffer [ 17 ] ;
buffer [ 0 ] = SM_CODE_IDENTITY_INFORMATION ;
swap128 ( sm_persistent_irk , & buffer [ 1 ] ) ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
return ;
}
if ( setup - > sm_key_distribution_send_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION ) {
setup - > sm_key_distribution_send_set & = ~ SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION ;
bd_addr_t local_address ;
uint8_t buffer [ 8 ] ;
buffer [ 0 ] = SM_CODE_IDENTITY_ADDRESS_INFORMATION ;
2015-03-01 20:51:08 +00:00
hci_le_advertisement_address ( & buffer [ 1 ] , local_address ) ;
2015-02-27 10:52:33 +00:00
bt_flip_addr ( & buffer [ 2 ] , local_address ) ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
return ;
}
if ( setup - > sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION ) {
setup - > sm_key_distribution_send_set & = ~ SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION ;
uint8_t buffer [ 17 ] ;
buffer [ 0 ] = SM_CODE_SIGNING_INFORMATION ;
swap128 ( setup - > sm_local_csrk , & buffer [ 1 ] ) ;
l2cap_send_connectionless ( connection - > sm_handle , L2CAP_CID_SECURITY_MANAGER_PROTOCOL , ( uint8_t * ) buffer , sizeof ( buffer ) ) ;
2015-02-27 14:17:45 +00:00
sm_timeout_reset ( connection ) ;
2015-02-27 10:52:33 +00:00
return ;
}
2014-01-05 19:21:33 +00:00
2015-02-27 10:52:33 +00:00
// keys are sent
if ( connection - > sm_role ) {
// slave -> receive master keys
connection - > sm_engine_state = SM_PH3_RECEIVE_KEYS ;
} else {
// master -> all done
connection - > sm_engine_state = SM_GENERAL_IDLE ;
sm_done_for_handle ( connection - > sm_handle ) ;
}
break ;
default :
break ;
}
// check again if active connection was released
if ( sm_active_connection ) break ;
2014-01-05 19:21:33 +00:00
}
}
2014-06-12 12:44:03 +00:00
2014-06-15 10:42:39 +00:00
// note: aes engine is ready as we just got the aes result
2014-06-12 10:32:55 +00:00
static void sm_handle_encryption_result ( uint8_t * data ) {
2014-06-12 13:14:43 +00:00
2014-06-12 13:38:17 +00:00
sm_aes128_state = SM_AES128_IDLE ;
2014-06-12 13:14:43 +00:00
2014-06-12 10:32:55 +00:00
if ( sm_central_ah_calculation_active ) {
sm_central_ah_calculation_active = 0 ;
// compare calulated address against connecting device
uint8_t hash [ 3 ] ;
swap24 ( data , hash ) ;
2014-06-12 15:07:01 +00:00
if ( memcmp ( & sm_central_device_address [ 3 ] , hash , 3 ) = = 0 ) {
2014-06-12 10:32:55 +00:00
// found
sm_central_device_matched = sm_central_device_test ;
sm_central_device_test = - 1 ;
2015-02-12 21:36:06 +00:00
sm_csrk_connection_source - > sm_csrk_lookup_state = CSRK_LOOKUP_IDLE ;
sm_csrk_connection_source = NULL ;
2014-06-12 15:07:01 +00:00
sm_notify_client ( SM_IDENTITY_RESOLVING_SUCCEEDED , sm_central_device_addr_type , sm_central_device_address , 0 , sm_central_device_matched ) ;
2015-03-03 21:38:29 +00:00
log_info ( " LE Device Lookup: matched resolvable private address " ) ;
2014-06-12 10:32:55 +00:00
return ;
}
// no match
sm_central_device_test + + ;
return ;
}
switch ( dkg_state ) {
case DKG_W4_IRK :
swap128 ( data , sm_persistent_irk ) ;
2014-08-15 21:26:50 +00:00
log_key ( " irk " , sm_persistent_irk ) ;
2014-06-12 10:32:55 +00:00
dkg_next_state ( ) ;
return ;
case DKG_W4_DHK :
swap128 ( data , sm_persistent_dhk ) ;
2014-08-15 21:26:50 +00:00
log_key ( " dhk " , sm_persistent_dhk ) ;
2014-06-12 10:32:55 +00:00
dkg_next_state ( ) ;
// SM INIT FINISHED, start application code - TODO untangle that
if ( sm_client_packet_handler )
{
2015-03-30 13:17:10 -07:00
uint8_t event [ ] = { BTSTACK_EVENT_STATE , 1 , HCI_STATE_WORKING } ;
2014-06-12 10:32:55 +00:00
sm_client_packet_handler ( HCI_EVENT_PACKET , 0 , ( uint8_t * ) event , sizeof ( event ) ) ;
}
return ;
default :
break ;
}
switch ( rau_state ) {
case RAU_W4_ENC :
swap24 ( data , & sm_random_address [ 3 ] ) ;
rau_next_state ( ) ;
return ;
default :
break ;
}
switch ( sm_cmac_state ) {
case CMAC_W4_SUBKEYS :
case CMAC_W4_MI :
case CMAC_W4_MLAST :
{
sm_key_t t ;
swap128 ( data , t ) ;
sm_cmac_handle_encryption_result ( t ) ;
}
return ;
default :
break ;
}
2015-02-12 16:16:42 +00:00
// retrieve sm_connection provided to sm_aes128_start_encryption
sm_connection_t * connection = sm_aes128_connection_source ;
if ( ! connection ) return ;
2014-06-15 15:27:04 +00:00
switch ( connection - > sm_engine_state ) {
case SM_PH2_C1_W4_ENC_A :
case SM_PH2_C1_W4_ENC_C :
2014-06-12 10:32:55 +00:00
{
sm_key_t t2 ;
swap128 ( data , t2 ) ;
2014-06-15 10:42:39 +00:00
sm_c1_t3 ( t2 , setup - > sm_m_address , setup - > sm_s_address , setup - > sm_c1_t3_value ) ;
2014-06-12 10:32:55 +00:00
}
2015-02-12 15:37:01 +00:00
sm_next_responding_state ( connection ) ;
2014-06-12 10:32:55 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH2_C1_W4_ENC_B :
2014-06-13 13:36:13 +00:00
swap128 ( data , setup - > sm_local_confirm ) ;
2014-08-15 21:26:50 +00:00
log_key ( " c1! " , setup - > sm_local_confirm ) ;
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH2_C1_SEND_PAIRING_CONFIRM ;
2014-06-12 10:32:55 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH2_C1_W4_ENC_D :
2014-06-12 10:32:55 +00:00
{
2014-06-13 13:36:13 +00:00
sm_key_t peer_confirm_test ;
swap128 ( data , peer_confirm_test ) ;
2014-08-15 21:26:50 +00:00
log_key ( " c1! " , peer_confirm_test ) ;
2014-06-13 13:36:13 +00:00
if ( memcmp ( setup - > sm_peer_confirm , peer_confirm_test , 16 ) ! = 0 ) {
setup - > sm_pairing_failed_reason = SM_REASON_CONFIRM_VALUE_FAILED ;
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED ;
2014-06-13 13:36:13 +00:00
return ;
}
2014-06-13 12:39:16 +00:00
if ( connection - > sm_role ) {
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH2_SEND_PAIRING_RANDOM ;
2014-06-13 12:39:16 +00:00
} else {
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH2_CALC_STK ;
2014-06-12 10:32:55 +00:00
}
}
return ;
2014-06-15 15:27:04 +00:00
case SM_PH2_W4_STK :
2014-06-13 12:42:10 +00:00
swap128 ( data , setup - > sm_ltk ) ;
sm_truncate_key ( setup - > sm_ltk , connection - > sm_actual_encryption_key_size ) ;
2014-08-15 21:26:50 +00:00
log_key ( " stk " , setup - > sm_ltk ) ;
2014-06-13 15:28:41 +00:00
if ( connection - > sm_role ) {
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY ;
2014-06-13 15:28:41 +00:00
} else {
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_INITIATOR_PH3_SEND_START_ENCRYPTION ;
2014-06-13 15:28:41 +00:00
}
2014-06-12 10:32:55 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH3_Y_W4_ENC : {
2014-06-12 10:32:55 +00:00
sm_key_t y128 ;
swap128 ( data , y128 ) ;
2014-06-13 18:37:12 +00:00
setup - > sm_local_y = READ_NET_16 ( y128 , 14 ) ;
2014-08-15 21:26:50 +00:00
log_info_hex16 ( " y " , setup - > sm_local_y ) ;
2014-06-12 10:32:55 +00:00
// PH3B3 - calculate EDIV
2014-06-13 18:37:12 +00:00
setup - > sm_local_ediv = setup - > sm_local_y ^ setup - > sm_local_div ;
2014-08-15 21:26:50 +00:00
log_info_hex16 ( " ediv " , setup - > sm_local_ediv ) ;
2014-06-12 10:32:55 +00:00
// PH3B4 - calculate LTK - enc
// LTK = d1(ER, DIV, 0))
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH3_LTK_GET_ENC ;
2014-06-12 10:32:55 +00:00
return ;
}
2014-06-15 15:27:04 +00:00
case SM_PH4_Y_W4_ENC : {
2014-06-12 10:32:55 +00:00
sm_key_t y128 ;
swap128 ( data , y128 ) ;
2014-06-13 18:37:12 +00:00
setup - > sm_local_y = READ_NET_16 ( y128 , 14 ) ;
2014-08-15 21:26:50 +00:00
log_info_hex16 ( " y " , setup - > sm_local_y ) ;
2014-06-15 10:26:41 +00:00
2014-06-12 10:32:55 +00:00
// PH3B3 - calculate DIV
2014-06-13 18:37:12 +00:00
setup - > sm_local_div = setup - > sm_local_y ^ setup - > sm_local_ediv ;
2014-08-15 21:26:50 +00:00
log_info_hex16 ( " ediv " , setup - > sm_local_ediv ) ;
2014-06-12 10:32:55 +00:00
// PH3B4 - calculate LTK - enc
// LTK = d1(ER, DIV, 0))
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH4_LTK_GET_ENC ;
2014-06-12 10:32:55 +00:00
return ;
}
2014-06-15 15:27:04 +00:00
case SM_PH3_LTK_W4_ENC :
2014-06-13 12:42:10 +00:00
swap128 ( data , setup - > sm_ltk ) ;
2014-08-15 21:26:50 +00:00
log_key ( " ltk " , setup - > sm_ltk ) ;
2014-06-15 10:26:41 +00:00
// calc CSRK next
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH3_CSRK_GET_ENC ;
2014-06-15 10:26:41 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH3_CSRK_W4_ENC :
2014-06-15 10:26:41 +00:00
swap128 ( data , setup - > sm_local_csrk ) ;
2014-08-15 21:26:50 +00:00
log_key ( " csrk " , setup - > sm_local_csrk ) ;
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH3_DISTRIBUTE_KEYS ;
2014-06-12 10:32:55 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH4_LTK_W4_ENC :
2014-06-13 12:42:10 +00:00
swap128 ( data , setup - > sm_ltk ) ;
sm_truncate_key ( setup - > sm_ltk , connection - > sm_actual_encryption_key_size ) ;
2014-08-15 21:26:50 +00:00
log_key ( " ltk " , setup - > sm_ltk ) ;
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH4_SEND_LTK ;
2014-06-12 10:32:55 +00:00
return ;
default :
break ;
}
}
2014-01-05 19:21:33 +00:00
2014-06-12 12:44:03 +00:00
// note: random generator is ready. this doesn NOT imply that aes engine is unused!
static void sm_handle_random_result ( uint8_t * data ) {
switch ( rau_state ) {
case RAU_W4_RANDOM :
// non-resolvable vs. resolvable
switch ( gap_random_adress_type ) {
case GAP_RANDOM_ADDRESS_RESOLVABLE :
// resolvable: use random as prand and calc address hash
// "The two most significant bits of prand shall be equal to ‘ 0’ and ‘ 1"
memcpy ( sm_random_address , data , 3 ) ;
sm_random_address [ 0 ] & = 0x3f ;
sm_random_address [ 0 ] | = 0x40 ;
rau_state = RAU_GET_ENC ;
break ;
case GAP_RANDOM_ADDRESS_NON_RESOLVABLE :
default :
// "The two most significant bits of the address shall be equal to ‘ 0’ ""
memcpy ( sm_random_address , data , 6 ) ;
sm_random_address [ 0 ] & = 0x3f ;
rau_state = RAU_SET_ADDRESS ;
break ;
}
return ;
default :
break ;
}
2015-02-26 14:30:51 +00:00
// retrieve sm_connection provided to sm_random_start
sm_connection_t * connection = sm_random_connection_source ;
2015-02-12 16:16:42 +00:00
if ( ! connection ) return ;
2014-06-15 15:27:04 +00:00
switch ( connection - > sm_engine_state ) {
case SM_PH2_W4_RANDOM_TK :
2014-06-12 12:44:03 +00:00
{
// map random to 0-999999 without speding much cycles on a modulus operation
2014-08-27 12:50:09 +00:00
uint32_t tk = READ_BT_32 ( data , 0 ) ;
2014-06-12 12:44:03 +00:00
tk = tk & 0xfffff ; // 1048575
if ( tk > = 999999 ) {
tk = tk - 999999 ;
}
sm_reset_tk ( ) ;
2014-06-12 21:16:47 +00:00
net_store_32 ( setup - > sm_tk , 12 , tk ) ;
2014-06-13 10:36:03 +00:00
if ( connection - > sm_role ) {
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE ;
2014-06-13 10:36:03 +00:00
} else {
2014-06-15 16:02:56 +00:00
connection - > sm_engine_state = SM_PH1_W4_USER_RESPONSE ;
2015-02-12 15:37:01 +00:00
sm_trigger_user_response ( connection ) ;
2014-06-13 10:36:03 +00:00
}
2014-06-12 12:44:03 +00:00
return ;
}
2014-06-15 15:27:04 +00:00
case SM_PH2_C1_W4_RANDOM_A :
2014-06-13 13:31:16 +00:00
memcpy ( & setup - > sm_local_random [ 0 ] , data , 8 ) ; // random endinaness
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH2_C1_GET_RANDOM_B ;
2014-06-12 12:44:03 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH2_C1_W4_RANDOM_B :
2014-06-13 13:31:16 +00:00
memcpy ( & setup - > sm_local_random [ 8 ] , data , 8 ) ; // random endinaness
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH2_C1_GET_ENC_A ;
2014-06-12 12:44:03 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH3_W4_RANDOM :
2014-06-13 18:37:12 +00:00
swap64 ( data , setup - > sm_local_rand ) ;
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand
setup - > sm_local_rand [ 7 ] = ( setup - > sm_local_rand [ 7 ] & 0xf0 ) + ( connection - > sm_actual_encryption_key_size - 1 ) ;
2014-06-12 12:44:03 +00:00
// no db for authenticated flag hack: store flag in bit 4 of LSB
2014-06-13 18:37:12 +00:00
setup - > sm_local_rand [ 7 ] = ( setup - > sm_local_rand [ 7 ] & 0xef ) + ( connection - > sm_connection_authenticated < < 4 ) ;
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH3_GET_DIV ;
2014-06-12 12:44:03 +00:00
return ;
2014-06-15 15:27:04 +00:00
case SM_PH3_W4_DIV :
2014-06-12 12:44:03 +00:00
// use 16 bit from random value as div
2014-06-13 18:37:12 +00:00
setup - > sm_local_div = READ_NET_16 ( data , 0 ) ;
2014-08-15 21:26:50 +00:00
log_info_hex16 ( " div " , setup - > sm_local_div ) ;
2014-06-15 15:27:04 +00:00
connection - > sm_engine_state = SM_PH3_Y_GET_ENC ;
2014-06-12 12:44:03 +00:00
return ;
default :
break ;
}
}
2015-02-26 16:11:09 +00:00
2014-04-28 21:02:26 +00:00
static void sm_event_packet_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2014-01-05 19:21:33 +00:00
2015-02-12 23:04:15 +00:00
sm_connection_t * sm_conn ;
uint16_t handle ;
2014-01-05 19:21:33 +00:00
switch ( packet_type ) {
case HCI_EVENT_PACKET :
switch ( packet [ 0 ] ) {
case BTSTACK_EVENT_STATE :
// bt stack activated, get started
if ( packet [ 2 ] = = HCI_STATE_WORKING ) {
2014-08-15 21:26:50 +00:00
log_info ( " HCI Working! " ) ;
2014-02-02 18:45:00 +00:00
dkg_state = sm_persistent_irk_ready ? DKG_CALC_DHK : DKG_CALC_IRK ;
2015-02-27 15:53:53 +00:00
rau_state = RAU_IDLE ;
2014-01-05 19:21:33 +00:00
sm_run ( ) ;
2014-01-05 19:54:00 +00:00
return ; // don't notify app packet handler just yet
2014-01-05 19:21:33 +00:00
}
break ;
case HCI_EVENT_LE_META :
switch ( packet [ 2 ] ) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE :
2014-02-04 20:48:43 +00:00
2014-08-15 21:26:50 +00:00
log_info ( " sm: connected " ) ;
2014-06-13 09:53:46 +00:00
2014-02-04 20:48:43 +00:00
if ( packet [ 3 ] ) return ; // connection failed
2015-02-12 23:04:15 +00:00
handle = READ_BT_16 ( packet , 4 ) ;
sm_conn = sm_get_connection_for_handle ( handle ) ;
if ( ! sm_conn ) break ;
2014-01-05 19:21:33 +00:00
2015-02-12 23:04:15 +00:00
sm_conn - > sm_handle = handle ;
sm_conn - > sm_role = packet [ 6 ] ;
sm_conn - > sm_peer_addr_type = packet [ 7 ] ;
bt_flip_addr ( sm_conn - > sm_peer_address , & packet [ 8 ] ) ;
2014-01-05 19:21:33 +00:00
2015-02-12 23:04:15 +00:00
log_info ( " New sm_conn, role %s " , sm_conn - > sm_role ? " slave " : " master " ) ;
2014-01-05 19:21:33 +00:00
2014-01-06 12:58:18 +00:00
// reset security properties
2015-02-12 23:04:15 +00:00
sm_conn - > sm_connection_encrypted = 0 ;
sm_conn - > sm_connection_authenticated = 0 ;
sm_conn - > sm_connection_authorization_state = AUTHORIZATION_UNKNOWN ;
2015-03-02 21:30:12 +00:00
sm_conn - > sm_le_db_index = - 1 ;
2014-01-06 12:07:15 +00:00
2015-02-26 15:31:52 +00:00
// prepare CSRK lookup (does not involve setup)
sm_conn - > sm_csrk_lookup_state = CSRK_LOOKUP_W4_READY ;
// just connected -> everything else happens in sm_run()
if ( sm_conn - > sm_role ) {
2015-05-21 15:45:55 +02:00
// slave - state already could be SM_RESPONDER_SEND_SECURITY_REQUEST instead
2015-05-21 15:48:14 +02:00
if ( sm_conn - > sm_engine_state = = SM_GENERAL_IDLE ) {
if ( sm_slave_request_security ) {
2015-05-21 15:45:55 +02:00
// request security if requested by app
sm_conn - > sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST ;
} else {
// otherwise, wait for pairing request
sm_conn - > sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_REQUEST ;
}
2015-02-26 21:32:16 +00:00
}
break ;
2015-02-26 15:31:52 +00:00
} else {
// master
2015-03-03 21:38:29 +00:00
sm_conn - > sm_engine_state = SM_INITIATOR_CONNECTED ;
2015-02-26 15:31:52 +00:00
}
2014-01-05 19:21:33 +00:00
break ;
case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST :
2015-02-12 23:04:15 +00:00
handle = READ_BT_16 ( packet , 3 ) ;
sm_conn = sm_get_connection_for_handle ( handle ) ;
if ( ! sm_conn ) break ;
log_info ( " LTK Request: state %u " , sm_conn - > sm_engine_state ) ;
if ( sm_conn - > sm_engine_state = = SM_RESPONDER_PH2_W4_LTK_REQUEST ) {
sm_conn - > sm_engine_state = SM_PH2_CALC_STK ;
2014-01-05 19:21:33 +00:00
break ;
}
// assume that we don't have a LTK for ediv == 0 and random == null
2015-02-27 15:53:53 +00:00
if ( READ_BT_16 ( packet , 13 ) = = 0 & & sm_is_null_random ( & packet [ 5 ] ) ) {
2014-08-15 21:26:50 +00:00
log_info ( " LTK Request: ediv & random are empty " ) ;
2015-03-03 21:38:29 +00:00
sm_conn - > sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY ;
2014-01-05 19:21:33 +00:00
break ;
}
2015-02-27 15:53:53 +00:00
// store rand and ediv
swap64 ( & packet [ 5 ] , sm_conn - > sm_local_rand ) ;
sm_conn - > sm_local_ediv = READ_BT_16 ( packet , 13 ) ;
2015-03-03 21:38:29 +00:00
sm_conn - > sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK ;
2014-01-05 19:21:33 +00:00
break ;
default :
break ;
}
break ;
case HCI_EVENT_ENCRYPTION_CHANGE :
2015-02-12 23:04:15 +00:00
handle = READ_BT_16 ( packet , 3 ) ;
sm_conn = sm_get_connection_for_handle ( handle ) ;
if ( ! sm_conn ) break ;
sm_conn - > sm_connection_encrypted = packet [ 5 ] ;
2015-02-27 15:53:53 +00:00
log_info ( " Encryption state change: %u, key size %u " , sm_conn - > sm_connection_encrypted ,
sm_conn - > sm_actual_encryption_key_size ) ;
2015-02-12 23:04:15 +00:00
if ( ! sm_conn - > sm_connection_encrypted ) break ;
2015-02-27 15:53:53 +00:00
// continue if part of initial pairing
2015-03-03 22:17:47 +00:00
switch ( sm_conn - > sm_engine_state ) {
case SM_INITIATOR_PH0_W4_CONNECTION_ENCRYPTED :
sm_conn - > sm_engine_state = SM_GENERAL_IDLE ;
sm_done_for_handle ( sm_conn - > sm_handle ) ;
break ;
case SM_PH2_W4_CONNECTION_ENCRYPTED :
if ( sm_conn - > sm_role ) {
sm_conn - > sm_engine_state = SM_PH3_GET_RANDOM ;
} else {
sm_conn - > sm_engine_state = SM_PH3_RECEIVE_KEYS ;
}
break ;
default :
break ;
2014-01-05 19:21:33 +00:00
}
break ;
case HCI_EVENT_DISCONNECTION_COMPLETE :
2015-02-12 23:04:15 +00:00
handle = READ_BT_16 ( packet , 3 ) ;
2015-02-26 16:11:09 +00:00
sm_done_for_handle ( handle ) ;
2015-02-12 23:04:15 +00:00
sm_conn = sm_get_connection_for_handle ( handle ) ;
if ( ! sm_conn ) break ;
2015-03-03 22:17:47 +00:00
// delete stored bonding on disconnect with authentication failure in ph0
if ( sm_conn - > sm_role = = 0
& & sm_conn - > sm_engine_state = = SM_INITIATOR_PH0_W4_CONNECTION_ENCRYPTED
& & packet [ 2 ] = = ERROR_CODE_AUTHENTICATION_FAILURE ) {
le_device_db_remove ( sm_conn - > sm_le_db_index ) ;
}
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_GENERAL_IDLE ;
sm_conn - > sm_handle = 0 ;
2014-01-05 19:21:33 +00:00
break ;
case HCI_EVENT_COMMAND_COMPLETE :
if ( COMMAND_COMPLETE_EVENT ( packet , hci_le_encrypt ) ) {
2014-06-12 10:32:55 +00:00
sm_handle_encryption_result ( & packet [ 6 ] ) ;
break ;
2014-01-05 19:21:33 +00:00
}
if ( COMMAND_COMPLETE_EVENT ( packet , hci_le_rand ) ) {
2014-06-12 12:44:03 +00:00
sm_handle_random_result ( & packet [ 6 ] ) ;
2014-01-05 19:21:33 +00:00
break ;
}
}
2014-01-05 19:54:00 +00:00
// forward packet to higher layer
2014-01-05 19:21:33 +00:00
if ( sm_client_packet_handler ) {
sm_client_packet_handler ( packet_type , 0 , packet , size ) ;
}
}
sm_run ( ) ;
}
2015-02-26 15:07:24 +00:00
2014-06-13 10:13:57 +00:00
static inline int sm_calc_actual_encryption_key_size ( int other ) {
if ( other < sm_min_encryption_key_size ) return 0 ;
if ( other < sm_max_encryption_key_size ) return other ;
return sm_max_encryption_key_size ;
}
2014-01-05 19:21:33 +00:00
2014-06-13 10:13:57 +00:00
/**
* @ return ok
*/
2015-05-13 10:30:46 +02:00
static int sm_validate_stk_generation_method ( void ) {
2014-06-13 10:13:57 +00:00
// check if STK generation method is acceptable by client
2014-06-13 10:19:18 +00:00
switch ( setup - > sm_stk_generation_method ) {
2014-06-13 10:13:57 +00:00
case JUST_WORKS :
return ( sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_JUST_WORKS ) ! = 0 ;
case PK_RESP_INPUT :
case PK_INIT_INPUT :
case OK_BOTH_INPUT :
return ( sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_PASSKEY ) ! = 0 ;
case OOB :
return ( sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_OOB ) ! = 0 ;
2014-08-11 22:09:43 +00:00
default :
return 0 ;
2014-06-13 10:13:57 +00:00
}
}
2015-02-27 10:52:33 +00:00
// helper for sm_packet_handler, calls sm_run on exit
static void sm_pdu_received_in_wrong_state ( sm_connection_t * sm_conn ) {
setup - > sm_pairing_failed_reason = SM_REASON_UNSPECIFIED_REASON ;
sm_conn - > sm_engine_state = SM_GENERAL_IDLE ;
sm_done_for_handle ( sm_conn - > sm_handle ) ;
}
2014-04-28 21:02:26 +00:00
static void sm_packet_handler ( uint8_t packet_type , uint16_t handle , uint8_t * packet , uint16_t size ) {
if ( packet_type = = HCI_EVENT_PACKET ) {
sm_event_packet_handler ( packet_type , handle , packet , size ) ;
return ;
}
if ( packet_type ! = SM_DATA_PACKET ) return ;
2015-02-12 23:04:15 +00:00
sm_connection_t * sm_conn = sm_get_connection_for_handle ( handle ) ;
if ( ! sm_conn ) return ;
2014-04-28 21:02:26 +00:00
if ( packet [ 0 ] = = SM_CODE_PAIRING_FAILED ) {
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_GENERAL_IDLE ;
2014-04-28 21:02:26 +00:00
return ;
}
2015-02-27 10:52:33 +00:00
log_debug ( " sm_packet_handler: state %u, pdu 0x%02x " , sm_conn - > sm_engine_state , packet [ 0 ] ) ;
2014-10-16 15:02:48 +00:00
2015-02-27 19:56:00 +00:00
int err ;
2015-02-27 16:06:07 +00:00
2015-02-12 23:04:15 +00:00
switch ( sm_conn - > sm_engine_state ) {
2014-04-28 21:02:26 +00:00
// a sm timeout requries a new physical connection
2014-06-15 15:27:04 +00:00
case SM_GENERAL_TIMEOUT :
2014-04-28 21:02:26 +00:00
return ;
2014-06-13 09:53:46 +00:00
// Initiator
2014-06-15 15:27:04 +00:00
case SM_INITIATOR_PH1_W4_PAIRING_RESPONSE :
2014-06-13 09:53:46 +00:00
if ( packet [ 0 ] ! = SM_CODE_PAIRING_RESPONSE ) {
2015-02-12 23:04:15 +00:00
sm_pdu_received_in_wrong_state ( sm_conn ) ;
2014-06-13 10:13:57 +00:00
break ;
2014-06-13 09:53:46 +00:00
}
// store pairing request
memcpy ( & setup - > sm_s_pres , packet , sizeof ( sm_pairing_packet_t ) ) ;
2015-02-27 19:56:00 +00:00
err = sm_stk_generation_init ( sm_conn ) ;
if ( err ) {
setup - > sm_pairing_failed_reason = err ;
sm_conn - > sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED ;
break ;
}
// generate random number first, if we need to show passkey
if ( setup - > sm_stk_generation_method = = PK_RESP_INPUT ) {
sm_conn - > sm_engine_state = SM_PH2_GET_RANDOM_TK ;
break ;
}
sm_conn - > sm_engine_state = SM_PH1_W4_USER_RESPONSE ;
sm_trigger_user_response ( sm_conn ) ;
2014-06-13 09:53:46 +00:00
break ;
2014-06-15 15:27:04 +00:00
case SM_INITIATOR_PH2_W4_PAIRING_CONFIRM :
2014-06-13 12:39:16 +00:00
if ( packet [ 0 ] ! = SM_CODE_PAIRING_CONFIRM ) {
2015-02-12 23:04:15 +00:00
sm_pdu_received_in_wrong_state ( sm_conn ) ;
2014-06-13 12:39:16 +00:00
break ;
}
// store s_confirm
2014-06-13 13:36:13 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_confirm ) ;
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_PH2_SEND_PAIRING_RANDOM ;
2014-06-13 12:39:16 +00:00
break ;
2014-06-15 15:27:04 +00:00
case SM_INITIATOR_PH2_W4_PAIRING_RANDOM :
2014-06-13 12:39:16 +00:00
if ( packet [ 0 ] ! = SM_CODE_PAIRING_RANDOM ) {
2015-02-12 23:04:15 +00:00
sm_pdu_received_in_wrong_state ( sm_conn ) ;
2014-06-13 12:39:16 +00:00
break ; ;
}
// received random value
2014-06-13 13:31:16 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_random ) ;
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_PH2_C1_GET_ENC_C ;
2014-06-13 12:39:16 +00:00
break ;
2014-06-13 09:53:46 +00:00
// Responder
2015-02-26 21:32:16 +00:00
case SM_GENERAL_IDLE :
case SM_RESPONDER_SEND_SECURITY_REQUEST :
2014-06-15 15:27:04 +00:00
case SM_RESPONDER_PH1_W4_PAIRING_REQUEST :
2014-04-28 21:02:26 +00:00
if ( packet [ 0 ] ! = SM_CODE_PAIRING_REQUEST ) {
2015-02-12 23:04:15 +00:00
sm_pdu_received_in_wrong_state ( sm_conn ) ;
2014-04-28 21:02:26 +00:00
break ; ;
}
2014-06-13 09:53:46 +00:00
// store pairing request
2015-02-26 21:32:16 +00:00
memcpy ( & sm_conn - > sm_m_preq , packet , sizeof ( sm_pairing_packet_t ) ) ;
sm_conn - > sm_engine_state = SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED ;
break ;
2014-04-28 21:02:26 +00:00
2014-06-15 15:27:04 +00:00
case SM_RESPONDER_PH1_W4_PAIRING_CONFIRM :
2014-04-28 21:02:26 +00:00
if ( packet [ 0 ] ! = SM_CODE_PAIRING_CONFIRM ) {
2015-02-12 23:04:15 +00:00
sm_pdu_received_in_wrong_state ( sm_conn ) ;
2014-04-28 21:02:26 +00:00
break ; ;
}
// received confirm value
2014-06-13 13:36:13 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_confirm ) ;
2014-04-28 21:02:26 +00:00
// notify client to hide shown passkey
2014-06-13 10:19:18 +00:00
if ( setup - > sm_stk_generation_method = = PK_INIT_INPUT ) {
2014-06-12 21:16:47 +00:00
sm_notify_client ( SM_PASSKEY_DISPLAY_CANCEL , setup - > sm_m_addr_type , setup - > sm_m_address , 0 , 0 ) ;
2014-04-28 21:02:26 +00:00
}
// handle user cancel pairing?
2014-06-12 21:16:47 +00:00
if ( setup - > sm_user_response = = SM_USER_RESPONSE_DECLINE ) {
setup - > sm_pairing_failed_reason = SM_REASON_PASSKEYT_ENTRY_FAILED ;
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED ;
2014-04-28 21:02:26 +00:00
break ;
}
// wait for user action?
2014-06-12 21:16:47 +00:00
if ( setup - > sm_user_response = = SM_USER_RESPONSE_PENDING ) {
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_PH1_W4_USER_RESPONSE ;
2014-04-28 21:02:26 +00:00
break ;
}
2014-06-15 16:02:56 +00:00
// calculate and send local_confirm
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_PH2_C1_GET_RANDOM_A ;
2014-04-28 21:02:26 +00:00
break ;
2014-06-15 15:27:04 +00:00
case SM_RESPONDER_PH2_W4_PAIRING_RANDOM :
2014-04-28 21:02:26 +00:00
if ( packet [ 0 ] ! = SM_CODE_PAIRING_RANDOM ) {
2015-02-12 23:04:15 +00:00
sm_pdu_received_in_wrong_state ( sm_conn ) ;
2014-04-28 21:02:26 +00:00
break ; ;
}
// received random value
2014-06-13 13:31:16 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_random ) ;
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_PH2_C1_GET_ENC_C ;
2014-04-28 21:02:26 +00:00
break ;
2014-06-15 15:27:04 +00:00
case SM_PH3_RECEIVE_KEYS :
2014-04-28 21:02:26 +00:00
switch ( packet [ 0 ] ) {
case SM_CODE_ENCRYPTION_INFORMATION :
2014-06-12 21:16:47 +00:00
setup - > sm_key_distribution_received_set | = SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION ;
2014-06-13 18:37:12 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_ltk ) ;
2014-04-28 21:02:26 +00:00
break ;
case SM_CODE_MASTER_IDENTIFICATION :
2014-06-12 21:16:47 +00:00
setup - > sm_key_distribution_received_set | = SM_KEYDIST_FLAG_MASTER_IDENTIFICATION ;
2014-06-13 18:37:12 +00:00
setup - > sm_peer_ediv = READ_BT_16 ( packet , 1 ) ;
swap64 ( & packet [ 3 ] , setup - > sm_peer_rand ) ;
2014-04-28 21:02:26 +00:00
break ;
case SM_CODE_IDENTITY_INFORMATION :
2014-06-12 21:16:47 +00:00
setup - > sm_key_distribution_received_set | = SM_KEYDIST_FLAG_IDENTITY_INFORMATION ;
2014-06-13 18:37:12 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_irk ) ;
2014-04-28 21:02:26 +00:00
break ;
case SM_CODE_IDENTITY_ADDRESS_INFORMATION :
2014-06-12 21:16:47 +00:00
setup - > sm_key_distribution_received_set | = SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION ;
2014-06-14 20:45:50 +00:00
setup - > sm_peer_addr_type = packet [ 1 ] ;
BD_ADDR_COPY ( setup - > sm_peer_address , & packet [ 2 ] ) ;
2014-04-28 21:02:26 +00:00
break ;
case SM_CODE_SIGNING_INFORMATION :
2014-06-12 21:16:47 +00:00
setup - > sm_key_distribution_received_set | = SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION ;
2015-03-02 21:12:29 +00:00
swap128 ( & packet [ 1 ] , setup - > sm_peer_csrk ) ;
2014-04-28 21:02:26 +00:00
break ;
default :
// Unexpected PDU
2014-08-15 21:26:50 +00:00
log_info ( " Unexpected PDU %u in SM_PH3_RECEIVE_KEYS " , packet [ 0 ] ) ;
2014-04-28 21:02:26 +00:00
break ;
}
// done with key distribution?
2014-06-13 15:50:55 +00:00
if ( sm_key_distribution_all_received ( ) ) {
2015-03-02 21:12:29 +00:00
// store, if: it's a public address, or, we got an IRK
if ( setup - > sm_peer_addr_type = = 0 | | ( setup - > sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION ) ) {
2015-03-02 21:30:12 +00:00
sm_conn - > sm_le_db_index = le_device_db_add ( setup - > sm_peer_addr_type , setup - > sm_peer_address , setup - > sm_peer_irk ) ;
2015-03-02 21:12:29 +00:00
}
2015-03-02 21:30:12 +00:00
if ( sm_conn - > sm_le_db_index > = 0 ) {
le_device_db_local_counter_set ( sm_conn - > sm_le_db_index , 0 ) ;
2015-03-02 21:12:29 +00:00
// store CSRK
if ( setup - > sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION ) {
2015-03-02 21:30:12 +00:00
le_device_db_csrk_set ( sm_conn - > sm_le_db_index , setup - > sm_peer_csrk ) ;
le_device_db_remote_counter_set ( sm_conn - > sm_le_db_index , 0 ) ;
2015-03-02 21:12:29 +00:00
}
// store encryption information as Central
if ( sm_conn - > sm_role = = 0
& & setup - > sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION
& & setup - > sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION ) {
2015-03-02 21:30:12 +00:00
le_device_db_encryption_set ( sm_conn - > sm_le_db_index , setup - > sm_peer_ediv , setup - > sm_peer_rand , setup - > sm_peer_ltk ) ;
2015-03-02 21:12:29 +00:00
}
}
2015-02-12 23:04:15 +00:00
if ( sm_conn - > sm_role ) {
sm_conn - > sm_engine_state = SM_GENERAL_IDLE ;
2015-02-27 10:52:33 +00:00
sm_done_for_handle ( sm_conn - > sm_handle ) ;
2014-06-13 15:50:55 +00:00
} else {
2015-02-12 23:04:15 +00:00
sm_conn - > sm_engine_state = SM_PH3_GET_RANDOM ;
2014-06-13 15:50:55 +00:00
}
2014-04-28 21:02:26 +00:00
}
break ;
default :
// Unexpected PDU
2015-02-12 23:04:15 +00:00
log_info ( " Unexpected PDU %u in state %u " , packet [ 0 ] , sm_conn - > sm_engine_state ) ;
2014-04-28 21:02:26 +00:00
break ;
}
// try to send preparared packet
sm_run ( ) ;
}
2014-01-05 20:19:00 +00:00
// Security Manager Client API
2015-03-01 20:51:08 +00:00
void sm_register_oob_data_callback ( int ( * get_oob_data_callback ) ( uint8_t addres_type , bd_addr_t addr , uint8_t * oob_data ) ) {
2014-01-05 20:19:00 +00:00
sm_get_oob_data = get_oob_data_callback ;
}
void sm_register_packet_handler ( btstack_packet_handler_t handler ) {
sm_client_packet_handler = handler ;
}
void sm_set_accepted_stk_generation_methods ( uint8_t accepted_stk_generation_methods ) {
sm_accepted_stk_generation_methods = accepted_stk_generation_methods ;
}
2014-01-08 13:08:41 +00:00
void sm_set_encryption_key_size_range ( uint8_t min_size , uint8_t max_size ) {
2014-01-05 20:19:00 +00:00
sm_min_encryption_key_size = min_size ;
sm_max_encryption_key_size = max_size ;
}
void sm_set_authentication_requirements ( uint8_t auth_req ) {
2014-06-12 22:15:27 +00:00
sm_auth_req = auth_req ;
2014-01-05 20:19:00 +00:00
}
void sm_set_io_capabilities ( io_capability_t io_capability ) {
2014-06-12 22:15:27 +00:00
sm_io_capabilities = io_capability ;
2014-01-05 20:19:00 +00:00
}
void sm_set_request_security ( int enable ) {
2014-06-12 21:54:00 +00:00
sm_slave_request_security = enable ;
2014-01-05 20:19:00 +00:00
}
2014-01-05 19:21:33 +00:00
void sm_set_er ( sm_key_t er ) {
memcpy ( sm_persistent_er , er , 16 ) ;
}
void sm_set_ir ( sm_key_t ir ) {
memcpy ( sm_persistent_ir , ir , 16 ) ;
}
2014-02-02 18:45:00 +00:00
// Testing support only
void sm_test_set_irk ( sm_key_t irk ) {
memcpy ( sm_persistent_irk , irk , 16 ) ;
sm_persistent_irk_ready = 1 ;
}
2014-01-30 10:32:09 +00:00
/**
* @ brief Trigger Security Request
*/
2015-02-12 23:04:15 +00:00
void sm_send_security_request ( uint16_t handle ) {
2015-04-24 12:12:37 +02:00
sm_connection_t * sm_conn = sm_get_connection_for_handle ( handle ) ;
2015-05-21 15:45:55 +02:00
switch ( sm_conn - > sm_engine_state ) {
case SM_GENERAL_IDLE :
case SM_RESPONDER_PH1_W4_PAIRING_REQUEST :
sm_conn - > sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST ;
sm_run ( ) ;
break ;
default :
break ;
}
2014-01-30 10:32:09 +00:00
}
2015-05-13 10:30:46 +02:00
void sm_init ( void ) {
2014-01-05 19:21:33 +00:00
// set some (BTstack default) ER and IR
int i ;
sm_key_t er ;
sm_key_t ir ;
for ( i = 0 ; i < 16 ; i + + ) {
er [ i ] = 0x30 + i ;
ir [ i ] = 0x90 + i ;
}
sm_set_er ( er ) ;
sm_set_ir ( ir ) ;
// defaults
sm_accepted_stk_generation_methods = SM_STK_GENERATION_METHOD_JUST_WORKS
| SM_STK_GENERATION_METHOD_OOB
| SM_STK_GENERATION_METHOD_PASSKEY ;
sm_max_encryption_key_size = 16 ;
sm_min_encryption_key_size = 7 ;
2014-06-12 13:38:17 +00:00
sm_cmac_state = CMAC_IDLE ;
2015-02-27 15:53:53 +00:00
dkg_state = DKG_W4_WORKING ;
rau_state = RAU_W4_WORKING ;
2014-06-12 13:38:17 +00:00
sm_aes128_state = SM_AES128_IDLE ;
2014-01-05 19:21:33 +00:00
sm_central_device_test = - 1 ; // no private address to resolve yet
sm_central_ah_calculation_active = 0 ;
2014-08-11 22:09:43 +00:00
gap_random_adress_update_period = 15 * 60 * 1000L ;
2014-01-05 19:21:33 +00:00
2015-02-26 16:11:09 +00:00
sm_active_connection = 0 ;
2014-01-05 19:21:33 +00:00
// attach to lower layers
l2cap_register_fixed_channel ( sm_packet_handler , L2CAP_CID_SECURITY_MANAGER_PROTOCOL ) ;
}
2015-02-27 10:52:33 +00:00
static sm_connection_t * sm_get_connection_for_handle ( uint16_t con_handle ) {
hci_connection_t * hci_con = hci_connection_for_handle ( ( hci_con_handle_t ) con_handle ) ;
if ( ! hci_con ) return NULL ;
return & hci_con - > sm_connection ;
2015-02-12 23:04:15 +00:00
}
2015-02-27 10:52:33 +00:00
2015-02-12 16:16:42 +00:00
static sm_connection_t * sm_get_connection ( uint8_t addr_type , bd_addr_t address ) {
2015-04-28 10:31:53 -04:00
hci_connection_t * hci_con = hci_connection_for_bd_addr_and_type ( address , ( bd_addr_type_t ) addr_type ) ;
2015-02-27 15:53:53 +00:00
if ( ! hci_con ) return NULL ;
2015-02-27 10:52:33 +00:00
return & hci_con - > sm_connection ;
2014-01-06 12:26:59 +00:00
}
2014-01-06 12:07:15 +00:00
// @returns 0 if not encrypted, 7-16 otherwise
int sm_encryption_key_size ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return 0 ; // wrong connection
if ( ! sm_conn - > sm_connection_encrypted ) return 0 ;
return sm_conn - > sm_actual_encryption_key_size ;
2014-01-06 12:07:15 +00:00
}
2014-01-06 12:26:59 +00:00
int sm_authenticated ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return 0 ; // wrong connection
if ( ! sm_conn - > sm_connection_encrypted ) return 0 ; // unencrypted connection cannot be authenticated
return sm_conn - > sm_connection_authenticated ;
2014-01-05 19:21:33 +00:00
}
2014-01-06 18:37:25 +00:00
authorization_state_t sm_authorization_state ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return AUTHORIZATION_UNKNOWN ; // wrong connection
if ( ! sm_conn - > sm_connection_encrypted ) return AUTHORIZATION_UNKNOWN ; // unencrypted connection cannot be authorized
if ( ! sm_conn - > sm_connection_authenticated ) return AUTHORIZATION_UNKNOWN ; // unauthenticatd connection cannot be authorized
return sm_conn - > sm_connection_authorization_state ;
2014-01-06 12:58:18 +00:00
}
// request authorization
void sm_request_authorization ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return ; // wrong connection
log_info ( " sm_request_authorization in role %u, state %u " , sm_conn - > sm_role , sm_conn - > sm_engine_state ) ;
if ( sm_conn - > sm_role ) {
2014-06-13 09:53:46 +00:00
// code has no effect so far
2015-02-12 16:16:42 +00:00
sm_conn - > sm_connection_authorization_state = AUTHORIZATION_PENDING ;
2014-06-13 09:53:46 +00:00
sm_notify_client ( SM_AUTHORIZATION_REQUEST , setup - > sm_m_addr_type , setup - > sm_m_address , 0 , 0 ) ;
} else {
// HACK
sm_authenticate_outgoing_connections = 1 ;
// used as a trigger to start central/master/initiator security procedures
2015-02-12 16:16:42 +00:00
if ( sm_conn - > sm_engine_state = = SM_INITIATOR_CONNECTED ) {
2015-02-26 21:32:16 +00:00
sm_conn - > sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST ;
2014-06-13 09:53:46 +00:00
}
}
2014-01-06 12:58:18 +00:00
}
// called by client app on authorization request
void sm_authorization_decline ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return ; // wrong connection
sm_conn - > sm_connection_authorization_state = AUTHORIZATION_DECLINED ;
2014-06-12 21:16:47 +00:00
sm_notify_client_authorization ( SM_AUTHORIZATION_RESULT , setup - > sm_m_addr_type , setup - > sm_m_address , 0 ) ;
2014-01-06 12:58:18 +00:00
}
void sm_authorization_grant ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return ; // wrong connection
sm_conn - > sm_connection_authorization_state = AUTHORIZATION_GRANTED ;
2014-06-12 21:16:47 +00:00
sm_notify_client_authorization ( SM_AUTHORIZATION_RESULT , setup - > sm_m_addr_type , setup - > sm_m_address , 1 ) ;
2014-01-06 12:58:18 +00:00
}
2014-01-06 12:26:59 +00:00
// GAP Bonding API
2014-01-05 19:21:33 +00:00
void sm_bonding_decline ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return ; // wrong connection
2014-06-12 21:16:47 +00:00
setup - > sm_user_response = SM_USER_RESPONSE_DECLINE ;
2014-01-05 19:21:33 +00:00
2015-02-12 16:16:42 +00:00
if ( sm_conn - > sm_engine_state = = SM_PH1_W4_USER_RESPONSE ) {
2015-02-26 16:11:09 +00:00
sm_done_for_handle ( sm_conn - > sm_handle ) ;
2014-06-12 21:16:47 +00:00
setup - > sm_pairing_failed_reason = SM_REASON_PASSKEYT_ENTRY_FAILED ;
2015-02-12 16:16:42 +00:00
sm_conn - > sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED ;
2014-01-05 19:21:33 +00:00
}
sm_run ( ) ;
}
void sm_just_works_confirm ( uint8_t addr_type , bd_addr_t address ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return ; // wrong connection
2014-06-12 21:16:47 +00:00
setup - > sm_user_response = SM_USER_RESPONSE_CONFIRM ;
2015-02-12 16:16:42 +00:00
if ( sm_conn - > sm_engine_state = = SM_PH1_W4_USER_RESPONSE ) {
sm_conn - > sm_engine_state = SM_PH2_C1_GET_RANDOM_A ;
2014-01-05 19:21:33 +00:00
}
sm_run ( ) ;
}
void sm_passkey_input ( uint8_t addr_type , bd_addr_t address , uint32_t passkey ) {
2015-02-12 16:16:42 +00:00
sm_connection_t * sm_conn = sm_get_connection ( addr_type , address ) ;
if ( ! sm_conn ) return ; // wrong connection
2014-01-05 19:21:33 +00:00
sm_reset_tk ( ) ;
2014-06-12 21:16:47 +00:00
net_store_32 ( setup - > sm_tk , 12 , passkey ) ;
setup - > sm_user_response = SM_USER_RESPONSE_PASSKEY ;
2015-02-12 16:16:42 +00:00
if ( sm_conn - > sm_engine_state = = SM_PH1_W4_USER_RESPONSE ) {
sm_conn - > sm_engine_state = SM_PH2_C1_GET_RANDOM_A ;
2014-01-05 19:21:33 +00:00
}
sm_run ( ) ;
}
2015-03-05 10:48:26 +00:00
/**
* @ brief Identify device in LE Device DB
* @ param handle
* @ returns index from le_device_db or - 1 if not found / identified
*/
int sm_le_device_index ( uint16_t handle ) {
sm_connection_t * sm_conn = sm_get_connection_for_handle ( handle ) ;
if ( ! sm_conn ) return - 1 ;
return sm_conn - > sm_le_db_index ;
}
2014-01-05 20:19:00 +00:00
// GAP LE API
void gap_random_address_set_mode ( gap_random_address_type_t random_address_type ) {
gap_random_address_update_stop ( ) ;
gap_random_adress_type = random_address_type ;
if ( random_address_type = = GAP_RANDOM_ADDRESS_TYPE_OFF ) return ;
gap_random_address_update_start ( ) ;
2014-02-02 18:45:00 +00:00
gap_random_address_trigger ( ) ;
2014-01-05 19:21:33 +00:00
}
2014-01-05 20:19:00 +00:00
void gap_random_address_set_update_period ( int period_ms ) {
gap_random_adress_update_period = period_ms ;
if ( gap_random_adress_type = = GAP_RANDOM_ADDRESS_TYPE_OFF ) return ;
gap_random_address_update_stop ( ) ;
gap_random_address_update_start ( ) ;
2015-03-30 13:17:10 -07:00
}