1#ifndef BLUETOE_SM_SECURITY_MANAGER_HPP
2#define BLUETOE_SM_SECURITY_MANAGER_HPP
10#include <bluetoe/codes.hpp>
11#include <bluetoe/address.hpp>
12#include <bluetoe/link_state.hpp>
13#include <bluetoe/pairing_status.hpp>
14#include <bluetoe/ll_meta_types.hpp>
15#include <bluetoe/oob_authentication.hpp>
17#include <bluetoe/io_capabilities.hpp>
18#include <bluetoe/l2cap_channels.hpp>
19#include <bluetoe/security_connection_data.hpp>
25 enum class sm_error_codes : std::uint8_t {
26 passkey_entry_failed = 0x01,
27 oob_not_available = 0x02,
28 authentication_requirements = 0x03,
29 confirm_value_failed = 0x04,
30 pairing_not_supported = 0x05,
31 encryption_key_size = 0x06,
32 command_not_supported = 0x07,
33 unspecified_reason = 0x08,
34 repeated_attempts = 0x09,
35 invalid_parameters = 0x0a,
36 dhkey_check_failed = 0x0b,
37 numeric_comparison_failed = 0x0c,
38 br_edr_pairing_in_progress = 0x0d,
39 crosstransport_key_derivation_generation_not_allowed = 0x0e
42 enum class sm_opcodes : std::uint8_t {
43 pairing_request = 0x01,
48 encryption_information,
49 central_identification,
51 identity_address_information,
56 pairing_keypress_notification
90 template <
class Obj, Obj& obj >
94 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
95 details::authentication_requirements_flags_meta_type,
96 details::bonding_data_base_meta_type,
97 details::key_distribution_meta_type {};
99 static constexpr std::uint8_t flags =
static_cast< std::uint8_t
>(
100 details::authentication_requirements_flags::bonding );
103 template <
class OtherConnectionData >
104 class bonding_db_data_t :
public OtherConnectionData
107 std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand )
const
109 const auto local_key = OtherConnectionData::find_key( ediv, rand );
111 if ( local_key.first )
114 return obj.find_key( ediv, rand, this->remote_address() );
117 template <
class Radio,
class Connection >
118 void arm_key_distribution( Radio& radio,
const Connection& connection )
120 pending_encryption_information =
true;
121 pending_central_identification =
true;
123 pending_key = obj.create_new_bond( radio, connection.remote_address() );
124 obj.store_bond( pending_key, connection );
127 template <
typename Connection >
128 void store_lesc_key_in_bond_db(
const details::uint128_t& key,
const Connection& connection )
130 obj.store_bond( details::longterm_key_t{ key, 0u, 0u }, connection );
133 template <
typename Connection >
134 void distribute_keys( std::uint8_t* output, std::size_t& out_size, Connection& connection )
138 if ( connection.security_attributes().is_encrypted )
140 if ( pending_encryption_information )
142 pending_encryption_information =
false;
144 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::encryption_information );
145 std::copy( pending_key.longterm_key.begin(), pending_key.longterm_key.end(), &output[ 1 ] );
146 std::fill( pending_key.longterm_key.begin(), pending_key.longterm_key.end(), 0 );
150 else if ( pending_central_identification )
152 pending_central_identification =
false;
154 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::central_identification );
155 details::write_16bit( &output[ 1 ], pending_key.ediv );
156 details::write_64bit( &output[ 3 ], pending_key.rand );
163 template <
typename Connection >
164 void restore_bonded_cccds( Connection& connection )
166 obj.restore_cccds( connection );
170 bool pending_encryption_information;
171 bool pending_central_identification;
172 details::longterm_key_t pending_key;
175 static constexpr std::uint8_t request_key_flags = 0x01;
181 struct no_bonding_data_base
183 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
184 details::authentication_requirements_flags_meta_type,
185 details::bonding_data_base_meta_type {};
187 template <
class OtherConnectionData >
188 struct bonding_db_data_t : OtherConnectionData
190 template <
class Radio,
class Connection >
191 void arm_key_distribution( Radio&,
const Connection& )
195 template <
typename Connection >
196 void distribute_keys( std::uint8_t*, std::size_t& out_size, Connection& )
201 template <
typename Connection >
202 void store_lesc_key_in_bond_db(
const details::uint128_t&,
const Connection& )
206 template <
typename Connection >
207 void restore_bonded_cccds( Connection& )
214 struct no_key_distribution
216 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
217 details::key_distribution_meta_type {};
219 static constexpr std::uint8_t request_key_flags = 0;
225 inline void error_response( details::sm_error_codes error_code, std::uint8_t* output, std::size_t& out_size )
227 output[ 0 ] =
static_cast< std::uint8_t
>( sm_opcodes::pairing_failed );
228 output[ 1 ] =
static_cast< std::uint8_t
>( error_code );
233 template <
typename ... Options >
234 struct accumulate_authentication_requirements_flags;
237 struct accumulate_authentication_requirements_flags< std::tuple<> >
239 static constexpr std::uint8_t flags = 0;
242 template <
typename Option,
class ... Options >
243 struct accumulate_authentication_requirements_flags< std::tuple< Option, Options... > > :
244 accumulate_authentication_requirements_flags< std::tuple< Options... > >
246 static constexpr std::uint8_t flags = Option::flags
247 | accumulate_authentication_requirements_flags< std::tuple< Options... > >::flags;
251 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
252 class security_manager_base :
253 protected details::find_by_meta_type<
254 details::oob_authentication_callback_meta_type,
256 details::no_oob_authentication >::type
259 static constexpr std::uint8_t authentication_requirements_flags =
260 accumulate_authentication_requirements_flags<
261 typename find_all_by_meta_type< authentication_requirements_flags_meta_type, Options... >::type
264 using bonding_data_base_t =
typename details::find_by_meta_type<
265 details::bonding_data_base_meta_type,
267 no_bonding_data_base >::type;
269 using key_distribution_t =
typename details::find_by_meta_type<
270 details::key_distribution_meta_type,
272 no_key_distribution >::type;
274 template <
class Connection >
275 void error_response( details::sm_error_codes error_code, std::uint8_t* output, std::size_t& out_size, Connection& state )
278 details::error_response( error_code, output, out_size );
281 using io_device_t = io_capabilities_matrix< Options... >;
283 static constexpr std::uint8_t min_max_key_size = 7;
284 static constexpr std::uint8_t max_max_key_size = 16;
285 static constexpr std::size_t pairing_req_resp_size = 7;
287 template <
class Connection >
288 void legacy_handle_pairing_request(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
290 void create_pairing_response( std::uint8_t* output, std::size_t& out_size,
const io_capabilities_t& io_caps );
292 template <
class Connection >
293 void legacy_handle_pairing_confirm(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
295 template <
class Connection >
296 void legacy_handle_pairing_random(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
298 template <
class Connection >
299 uint128_t legacy_create_temporary_key( Connection& );
301 template <
class Connection >
302 uint128_t legacy_temporary_key(
const Connection& )
const;
304 details::legacy_pairing_algorithm legacy_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t auth_req,
bool has_oob_data );
306 details::uint128_t legacy_c1_p1(
307 const std::uint8_t* input,
const std::uint8_t* output,
311 details::uint128_t legacy_c1_p2(
315 static constexpr std::size_t public_key_exchange_size = 65;
316 static constexpr std::size_t pairing_confirm_size = 17;
317 static constexpr std::size_t pairing_random_size = 17;
318 static constexpr std::size_t pairing_dhkey_check_size = 17;
320 template <
class Connection >
321 void lesc_handle_pairing_request(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
323 template <
class Connection >
324 void lesc_handle_pairing_public_key(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
326 template <
class Connection >
327 void lesc_handle_pairing_random(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
329 template <
class Connection >
330 void lesc_handle_pairing_dhkey_check(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
332 template <
class Connection >
333 bool lesc_security_manager_output_available( Connection& )
const;
335 template <
class Connection >
336 void lesc_l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
338 details::io_capabilities_t legacy_local_io_caps()
const;
339 details::io_capabilities_t lesc_local_io_caps()
const;
341 details::lesc_pairing_algorithm lesc_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t auth_req,
bool has_oob_data );
343 SecurityFunctions& security_functions()
345 return static_cast< SecurityFunctions&
>( *this );
348 const SecurityFunctions& security_functions()
const
350 return static_cast< const SecurityFunctions&
>( *this );
354 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
355 class legacy_security_manager_impl :
public security_manager_base< SecurityFunctions, ConnectionData, Options... >
360 template <
class Connection >
361 void l2cap_input(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
363 template <
class Connection >
364 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
366 static constexpr std::uint16_t channel_id = l2cap_channel_ids::sm;
367 static constexpr std::size_t minimum_channel_mtu_size = default_att_mtu_size;
368 static constexpr std::size_t maximum_channel_mtu_size = default_att_mtu_size;
370 using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;
372 template <
class OtherConnectionData >
373 using channel_data_t =
typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;
377 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
378 class lesc_security_manager_impl :
public security_manager_base< SecurityFunctions, ConnectionData, Options... >
382 template <
class Connection >
383 void l2cap_input(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
385 template <
class Connection >
386 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
388 static constexpr std::uint16_t channel_id = l2cap_channel_ids::sm;
389 static constexpr std::size_t minimum_channel_mtu_size = default_lesc_mtu_size;
390 static constexpr std::size_t maximum_channel_mtu_size = default_lesc_mtu_size;
392 using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;
394 template <
class OtherConnectionData >
395 using channel_data_t =
typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;
399 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
400 class security_manager_impl :
public security_manager_base< SecurityFunctions, ConnectionData, Options... >
404 template <
class Connection >
405 void l2cap_input(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
407 template <
class Connection >
408 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
410 static constexpr std::uint16_t channel_id = l2cap_channel_ids::sm;
411 static constexpr std::size_t minimum_channel_mtu_size = default_lesc_mtu_size;
412 static constexpr std::size_t maximum_channel_mtu_size = default_lesc_mtu_size;
414 using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;
416 template <
class OtherConnectionData >
417 using channel_data_t =
typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;
420 using security_manager_base< SecurityFunctions, ConnectionData, Options... >::security_functions;
422 template <
class Connection >
423 void handle_pairing_request(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
454 template <
typename SecurityFunctions,
typename ... Options >
455 using impl = details::legacy_security_manager_impl< SecurityFunctions, details::legacy_security_connection_data, Options... >;
457 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
458 details::security_manager_meta_type {};
485 template <
typename SecurityFunctions,
typename ... Options >
486 using impl = details::lesc_security_manager_impl< SecurityFunctions, details::lesc_security_connection_data, Options... >;
488 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
489 details::security_manager_meta_type {};
513 template <
typename SecurityFunctions,
typename ... Options >
514 using impl = details::security_manager_impl< SecurityFunctions, details::security_connection_data, Options... >;
516 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
517 details::security_manager_meta_type {};
536 template <
typename SecurityFunctions,
typename ... >
540 template <
class OtherConnectionData >
541 class channel_data_t :
public OtherConnectionData
548 device_pairing_status local_device_pairing_status()
const
550 return bluetoe::device_pairing_status::no_key;
555 template <
class Connection >
556 void l2cap_input(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );
558 template <
class Connection >
559 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
561 static constexpr std::uint16_t channel_id = l2cap_channel_ids::sm;
562 static constexpr std::size_t minimum_channel_mtu_size = 0;
563 static constexpr std::size_t maximum_channel_mtu_size = 0;
566 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
567 details::security_manager_meta_type {};
579 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
580 details::authentication_requirements_flags_meta_type {};
582 static constexpr std::uint8_t flags =
static_cast< std::uint8_t
>(
583 details::authentication_requirements_flags::bonding );
594 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
595 details::authentication_requirements_flags_meta_type {};
597 static constexpr std::uint8_t flags =
static_cast< std::uint8_t
>(
598 details::authentication_requirements_flags::mitm );
609 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
610 details::authentication_requirements_flags_meta_type {};
612 static constexpr std::uint8_t flags =
static_cast< std::uint8_t
>(
613 details::authentication_requirements_flags::keypress );
621 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
622 template <
class Connection >
623 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_handle_pairing_request(
624 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
626 using namespace details;
628 if ( in_size != pairing_req_resp_size )
629 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
631 if ( state.state() != details::sm_pairing_state::idle )
632 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
634 const std::uint8_t io_capability = input[ 1 ];
635 const std::uint8_t oob_data_flag = input[ 2 ];
636 const std::uint8_t auth_req = input[ 3 ] & 0x1f;
637 const std::uint8_t max_key_size = input[ 4 ];
638 const std::uint8_t initiator_key_distribution = input[ 5 ];
639 const std::uint8_t responder_key_distribution = input[ 6 ];
642 ( io_capability >
static_cast< std::uint8_t
>( io_capabilities::last ) )
643 || ( oob_data_flag & ~0x01 )
644 || ( max_key_size < min_max_key_size || max_key_size > max_max_key_size )
645 || ( initiator_key_distribution & 0xf0 )
646 || ( responder_key_distribution & 0xf0 )
649 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
652 this->request_oob_data_presents_for_remote_device( state.remote_address() );
653 state.pairing_algorithm( legacy_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );
655 create_pairing_response( output, out_size, legacy_local_io_caps() );
657 const details::uint128_t srand = security_functions().create_srand();
658 const details::uint128_t p1 = legacy_c1_p1( input, output, state.remote_address(), security_functions().local_address() );
659 const details::uint128_t p2 = legacy_c1_p2( state.remote_address(), security_functions().local_address() );
661 state.legacy_pairing_request( srand, p1, p2 );
664 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
665 inline void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::create_pairing_response( std::uint8_t* output, std::size_t& out_size,
const io_capabilities_t& io_caps )
667 out_size = pairing_req_resp_size;
668 output[ 0 ] =
static_cast< std::uint8_t
>( sm_opcodes::pairing_response );
669 output[ 1 ] = io_caps[ 0 ];
670 output[ 2 ] = io_caps[ 1 ];
671 output[ 3 ] = io_caps[ 2 ];
672 output[ 4 ] = max_max_key_size;
674 output[ 6 ] = key_distribution_t::request_key_flags;
677 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
678 template <
class Connection >
679 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_handle_pairing_confirm(
680 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
682 using namespace details;
684 static constexpr std::size_t request_size = 17;
686 if ( in_size != request_size )
687 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
689 if ( state.state() != sm_pairing_state::legacy_pairing_requested )
690 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
693 state.pairing_confirm( &input[ 1 ], &input[ request_size ] );
695 out_size = request_size;
696 output[ 0 ] =
static_cast< std::uint8_t
>( sm_opcodes::pairing_confirm );
698 const auto temp_key = legacy_create_temporary_key( state );
700 io_device_t::sm_pairing_numeric_output( temp_key );
702 const auto sconfirm = security_functions().c1( temp_key, state.srand(), state.c1_p1(), state.c1_p2() );
703 std::copy( sconfirm.begin(), sconfirm.end(), &output[ 1 ] );
706 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
707 template <
class Connection >
708 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_handle_pairing_random(
709 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
711 using namespace details;
713 static constexpr std::size_t pairing_random_size = 17;
715 if ( in_size != pairing_random_size )
716 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
718 if ( state.state() != sm_pairing_state::legacy_pairing_confirmed )
719 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
722 std::copy( &input[ 1 ], &input[ pairing_random_size ], mrand.begin() );
723 const uint128_t temp_key = legacy_temporary_key( state );
725 const auto mconfirm = security_functions().c1( temp_key, mrand, state.c1_p1(), state.c1_p2() );
727 if ( mconfirm != state.mconfirm() )
728 return this->error_response( sm_error_codes::confirm_value_failed, output, out_size, state );
730 out_size = pairing_random_size;
731 output[ 0 ] =
static_cast< std::uint8_t
>( sm_opcodes::pairing_random );
733 const auto srand = state.srand();
734 std::copy( srand.begin(), srand.end(), &output[ 1 ] );
736 const auto stk = security_functions().s1( temp_key, srand, mrand );
737 state.legacy_pairing_completed( stk );
738 state.arm_key_distribution( security_functions(), state );
741 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
742 template <
class Connection >
743 details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_create_temporary_key( Connection& state )
745 const auto algo = state.legacy_pairing_algorithm();
749 case legacy_pairing_algorithm::oob_authentication:
750 return this->get_oob_data_for_last_remote_device();
752 case legacy_pairing_algorithm::passkey_entry_display:
754 const auto key = security_functions().create_passkey();
755 state.passkey( key );
760 case legacy_pairing_algorithm::passkey_entry_input:
763 const auto key = io_device_t::sm_pairing_passkey();
764 state.passkey( key );
773 return uint128_t( { 0 } );
776 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
777 template <
class Connection >
778 details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_temporary_key(
const Connection& state )
const
780 const auto algo = state.legacy_pairing_algorithm();
784 case legacy_pairing_algorithm::oob_authentication:
785 return this->get_oob_data_for_last_remote_device();
787 case legacy_pairing_algorithm::passkey_entry_display:
788 case legacy_pairing_algorithm::passkey_entry_input:
789 return state.passkey();
795 return uint128_t( { 0 } );
798 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
799 details::legacy_pairing_algorithm details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t ,
bool has_oob_data )
801 if ( oob_data_flag && has_oob_data )
802 return details::legacy_pairing_algorithm::oob_authentication;
804 return io_device_t::select_legacy_pairing_algorithm( io_capability );
807 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
808 inline details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_c1_p1(
809 const std::uint8_t* input,
const std::uint8_t* output,
813 details::uint128_t result{ {
814 std::uint8_t( initiating_device.
is_random() ? 0x01 : 0x00 ),
815 std::uint8_t( responding_device.
is_random() ? 0x01 : 0x00 ) } };
817 std::copy( input, input + pairing_req_resp_size, &result[ 2 ] );
818 std::copy( output, output + pairing_req_resp_size, &result[ 2 + pairing_req_resp_size ] );
823 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
824 inline details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_c1_p2(
828 static constexpr std::size_t address_size_in_bytes = 6;
829 static constexpr std::uint8_t padding = 0;
831 details::uint128_t result;
833 std::copy( responding_device.
begin(), responding_device.
end(), result.begin() );
834 std::copy( initiating_device.
begin(), initiating_device.
end(), std::next( result.begin(), address_size_in_bytes ) );
835 std::fill( std::next( result.begin(), 2 * address_size_in_bytes ), result.end(), padding );
840 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
841 template <
class Connection >
842 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_request(
843 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
845 using namespace details;
847 if ( in_size != pairing_req_resp_size )
848 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
850 if ( state.state() != details::sm_pairing_state::idle )
851 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
853 const std::uint8_t io_capability = input[ 1 ];
854 const std::uint8_t oob_data_flag = input[ 2 ];
855 const std::uint8_t auth_req = input[ 3 ];
856 const std::uint8_t max_key_size = input[ 4 ];
857 const std::uint8_t initiator_key_distribution = input[ 5 ];
858 const std::uint8_t responder_key_distribution = input[ 6 ];
861 ( io_capability >
static_cast< std::uint8_t
>( io_capabilities::last ) )
862 || ( oob_data_flag & ~0x01 )
863 || ( max_key_size < min_max_key_size || max_key_size > max_max_key_size )
864 || ( initiator_key_distribution & 0xf0 )
865 || ( responder_key_distribution & 0xf0 )
868 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
871 if ( ( auth_req &
static_cast< std::uint8_t
>( authentication_requirements_flags::secure_connections ) ) == 0 )
872 return this->error_response( sm_error_codes::pairing_not_supported, output, out_size, state );
874 const io_capabilities_t remote_io_caps = {{ io_capability, oob_data_flag, auth_req }};
876 state.pairing_algorithm( lesc_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );
877 state.pairing_requested( remote_io_caps );
878 create_pairing_response( output, out_size, lesc_local_io_caps() );
881 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
882 details::io_capabilities_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_local_io_caps()
const
884 static constexpr std::uint8_t oob_authentication_data_not_present = 0x00;
885 static constexpr std::uint8_t oob_authentication_data_from_remote_device_present = 0x01;
888 static_cast< std::uint8_t
>( io_device_t::get_io_capabilities() ),
889 this->has_oob_data_for_remote_device()
890 ? oob_authentication_data_from_remote_device_present
891 : oob_authentication_data_not_present,
892 authentication_requirements_flags }};
895 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
896 details::io_capabilities_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_local_io_caps()
const
899 static_cast< std::uint8_t
>( io_device_t::get_io_capabilities() ),
901 authentication_requirements_flags |
static_cast< std::uint8_t
>( details::authentication_requirements_flags::secure_connections ) }};
904 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
905 template <
class Connection >
906 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_public_key(
907 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
909 if ( in_size != public_key_exchange_size )
910 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
912 if ( state.state() != details::sm_pairing_state::lesc_pairing_requested )
913 return this->error_response( details::sm_error_codes::unspecified_reason, output, out_size, state );
915 assert( out_size >= public_key_exchange_size );
917 if ( !security_functions().is_valid_public_key( &input[ 1 ] ) )
918 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
920 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::pairing_public_key );
922 out_size = public_key_exchange_size;
923 const auto& keys = security_functions().generate_keys();
924 const auto& nonce = security_functions().select_random_nonce();
926 state.public_key_exchanged( keys.second, keys.first, &input[ 1 ], nonce );
927 std::copy( keys.first.begin(), keys.first.end(), &output[ 1 ] );
930 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
931 template <
class Connection >
932 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_random(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
934 if ( in_size != pairing_random_size )
935 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
937 if ( state.state() != details::sm_pairing_state::lesc_pairing_confirm_send )
938 return this->error_response( details::sm_error_codes::unspecified_reason, output, out_size, state );
940 state.pairing_random_exchanged( input + 1 );
942 if ( state.lesc_pairing_algorithm() == lesc_pairing_algorithm::numeric_comparison )
944 io_device_t::sm_pairing_numeric_compare_output( state, security_functions() );
945 io_device_t::sm_pairing_request_yes_no( state );
948 if ( state.state() == details::sm_pairing_state::user_response_failed )
949 return this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );
951 const auto& nonce = state.local_nonce();
952 out_size = pairing_random_size;
953 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::pairing_random );
954 std::copy( nonce.begin(), nonce.end(), &output[ 1 ] );
957 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
958 template <
class Connection >
959 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_dhkey_check(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
961 if ( in_size != pairing_dhkey_check_size )
962 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
964 static const auto expected_states = {
965 details::sm_pairing_state::lesc_pairing_random_exchanged,
966 details::sm_pairing_state::user_response_wait,
967 details::sm_pairing_state::user_response_failed,
968 details::sm_pairing_state::user_response_success
971 if ( std::find( std::begin( expected_states ), std::end( expected_states ), state.state() ) == std::end( expected_states ) )
972 return this->error_response( details::sm_error_codes::unspecified_reason, output, out_size, state );
974 if ( state.state() == details::sm_pairing_state::user_response_wait )
978 else if ( state.state() == details::sm_pairing_state::user_response_failed )
980 return this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );
984 const details::ecdh_shared_secret_t dh_key = security_functions().p256( state.local_private_key(), state.remote_public_key() );
986 details::uint128_t mac_key;
987 details::uint128_t ltk;
988 static const details::uint128_t zero = {{ 0 }};
990 std::tie( mac_key, ltk ) = security_functions().f5( dh_key, state.remote_nonce(), state.local_nonce(), state.remote_address(), security_functions().local_address() );
992 const auto calc_ea = security_functions().f6( mac_key, state.remote_nonce(), state.local_nonce(), zero, state.remote_io_caps(), state.remote_address(), security_functions().local_address() );
994 if ( !std::equal( calc_ea.begin(), calc_ea.end(), &input[ 1 ] ) )
995 return this->error_response( details::sm_error_codes::dhkey_check_failed, output, out_size, state );
997 const auto eb = security_functions().f6( mac_key, state.local_nonce(), state.remote_nonce(), zero, lesc_local_io_caps(), security_functions().local_address(), state.remote_address() );
999 out_size = pairing_dhkey_check_size;
1000 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::pairing_dhkey_check );
1001 std::copy( eb.begin(), eb.end(), &output[ 1 ] );
1003 state.lesc_pairing_completed( ltk );
1004 state.store_lesc_key_in_bond_db( ltk, state );
1008 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1009 template <
class Connection >
1010 bool details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_security_manager_output_available( Connection& state )
const
1012 return state.state() == details::sm_pairing_state::lesc_public_keys_exchanged
1013 || state.state() == details::sm_pairing_state::user_response_success
1014 || state.state() == details::sm_pairing_state::user_response_failed;
1017 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1018 template <
class Connection >
1019 void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )
1021 assert( lesc_security_manager_output_available( state ) );
1023 if ( state.state() == details::sm_pairing_state::lesc_public_keys_exchanged )
1025 const auto& Nb = state.local_nonce();
1026 const std::uint8_t* Pkax = state.remote_public_key_x();
1027 const std::uint8_t* PKbx = state.local_public_key_x();
1029 const auto confirm = security_functions().f4( PKbx, Pkax, Nb, 0 );
1031 out_size = this->pairing_confirm_size;
1032 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::pairing_confirm );
1033 std::copy( confirm.begin(), confirm.end(), &output[ 1 ] );
1035 state.pairing_confirm_send();
1037 else if ( state.state() == details::sm_pairing_state::user_response_success )
1039 const details::ecdh_shared_secret_t dh_key = security_functions().p256( state.local_private_key(), state.remote_public_key() );
1041 details::uint128_t mac_key;
1042 details::uint128_t ltk;
1043 static const details::uint128_t zero = {{ 0 }};
1045 std::tie( mac_key, ltk ) = security_functions().f5( dh_key, state.remote_nonce(), state.local_nonce(), state.remote_address(), security_functions().local_address() );
1046 const auto eb = security_functions().f6( mac_key, state.local_nonce(), state.remote_nonce(), zero, this->lesc_local_io_caps(), security_functions().local_address(), state.remote_address() );
1048 out_size = this->pairing_dhkey_check_size;
1049 output[ 0 ] =
static_cast< std::uint8_t
>( details::sm_opcodes::pairing_dhkey_check );
1050 std::copy( eb.begin(), eb.end(), &output[ 1 ] );
1052 state.lesc_pairing_completed( ltk );
1053 state.store_lesc_key_in_bond_db( ltk, state );
1057 this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );
1062 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1063 details::lesc_pairing_algorithm details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t ,
bool has_oob_data )
1065 if ( oob_data_flag || has_oob_data )
1066 return details::lesc_pairing_algorithm::oob_authentication;
1068 return io_device_t::select_lesc_pairing_algorithm( io_capability );
1072 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1073 template <
class Connection >
1074 void details::legacy_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_input(
1075 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
1077 using namespace bluetoe::details;
1081 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1083 assert( in_size != 0 );
1084 assert( out_size >= default_att_mtu_size );
1086 const sm_opcodes opcode =
static_cast< sm_opcodes
>( input[ 0 ] );
1090 case sm_opcodes::pairing_request:
1091 this->legacy_handle_pairing_request( input, in_size, output, out_size, state );
1093 case sm_opcodes::pairing_confirm:
1094 this->legacy_handle_pairing_confirm( input, in_size, output, out_size, state );
1096 case sm_opcodes::pairing_random:
1097 this->legacy_handle_pairing_random( input, in_size, output, out_size, state );
1100 this->error_response( sm_error_codes::command_not_supported, output, out_size, state );
1104 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1105 template <
class Connection >
1106 void details::legacy_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )
1108 state.distribute_keys( output, out_size, state );
1112 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1113 template <
class Connection >
1114 void details::lesc_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_input(
1115 const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
1117 using namespace bluetoe::details;
1121 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1123 assert( in_size != 0 );
1124 assert( out_size >= default_att_mtu_size );
1126 const sm_opcodes opcode =
static_cast< sm_opcodes
>( input[ 0 ] );
1130 case sm_opcodes::pairing_request:
1131 this->lesc_handle_pairing_request( input, in_size, output, out_size, state );
1133 case sm_opcodes::pairing_public_key:
1134 this->lesc_handle_pairing_public_key( input, in_size, output, out_size, state );
1136 case sm_opcodes::pairing_random:
1137 this->lesc_handle_pairing_random( input, in_size, output, out_size, state );
1139 case sm_opcodes::pairing_dhkey_check:
1140 this->lesc_handle_pairing_dhkey_check( input, in_size, output, out_size, state );
1143 this->error_response( sm_error_codes::command_not_supported, output, out_size, state );
1147 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1148 template <
class Connection >
1149 void details::lesc_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )
1151 if ( this->lesc_security_manager_output_available( state ) )
1153 this->lesc_l2cap_output( output, out_size, state );
1162 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1163 template <
class Connection >
1164 void details::security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_input(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
1166 using namespace bluetoe::details;
1170 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1172 assert( in_size != 0 );
1173 assert( out_size >= default_att_mtu_size );
1175 const sm_opcodes opcode =
static_cast< sm_opcodes
>( input[ 0 ] );
1179 case sm_opcodes::pairing_request:
1180 handle_pairing_request( input, in_size, output, out_size, state );
1182 case sm_opcodes::pairing_confirm:
1183 this->legacy_handle_pairing_confirm( input, in_size, output, out_size, state );
1185 case sm_opcodes::pairing_random:
1186 if ( state.state() == sm_pairing_state::legacy_pairing_confirmed )
1188 this->legacy_handle_pairing_random( input, in_size, output, out_size, state );
1192 this->lesc_handle_pairing_random( input, in_size, output, out_size, state );
1195 case sm_opcodes::pairing_public_key:
1196 this->lesc_handle_pairing_public_key( input, in_size, output, out_size, state );
1198 case sm_opcodes::pairing_dhkey_check:
1199 this->lesc_handle_pairing_dhkey_check( input, in_size, output, out_size, state );
1202 this->error_response( sm_error_codes::command_not_supported, output, out_size, state );
1206 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1207 template <
class Connection >
1208 void details::security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )
1210 if ( this->lesc_security_manager_output_available( state ) )
1212 this->lesc_l2cap_output( output, out_size, state );
1216 state.distribute_keys( output, out_size, state );
1220 template <
typename SecurityFunctions,
template <
class OtherConnectionData >
class ConnectionData,
typename ... Options >
1221 template <
class Connection >
1222 void details::security_manager_impl< SecurityFunctions, ConnectionData, Options... >::handle_pairing_request(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )
1224 using namespace details;
1226 if ( in_size != this->pairing_req_resp_size )
1227 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1229 if ( state.state() != details::sm_pairing_state::idle )
1230 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
1232 const std::uint8_t io_capability = input[ 1 ];
1233 const std::uint8_t oob_data_flag = input[ 2 ];
1234 const std::uint8_t auth_req = input[ 3 ];
1235 const std::uint8_t max_key_size = input[ 4 ];
1236 const std::uint8_t initiator_key_distribution = input[ 5 ];
1237 const std::uint8_t responder_key_distribution = input[ 6 ];
1240 ( io_capability >
static_cast< std::uint8_t
>( io_capabilities::last ) )
1241 || ( oob_data_flag & ~0x01 )
1242 || ( max_key_size < this->min_max_key_size || max_key_size > this->max_max_key_size )
1243 || ( initiator_key_distribution & 0xf0 )
1244 || ( responder_key_distribution & 0xf0 )
1247 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1250 this->request_oob_data_presents_for_remote_device( state.remote_address() );
1252 const bool lesc_pairing = ( auth_req &
static_cast< std::uint8_t
>(authentication_requirements_flags::secure_connections ) );
1256 const io_capabilities_t remote_io_caps = {{ io_capability, oob_data_flag, auth_req }};
1257 state.pairing_algorithm( this->lesc_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );
1258 state.pairing_requested( remote_io_caps );
1260 this->create_pairing_response( output, out_size, this->lesc_local_io_caps() );
1264 state.pairing_algorithm( this->legacy_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );
1266 this->create_pairing_response( output, out_size, this->lesc_local_io_caps() );
1268 const details::uint128_t srand = security_functions().create_srand();
1269 const details::uint128_t p1 = this->legacy_c1_p1( input, output, state.remote_address(), security_functions().local_address() );
1270 const details::uint128_t p2 = this->legacy_c1_p2( state.remote_address(), security_functions().local_address() );
1272 state.legacy_pairing_request( srand, p1, p2 );
1277 template <
typename SecurityFunctions,
typename ...Os >
1278 template <
class Connection >
1279 void no_security_manager::impl< SecurityFunctions, Os... >::l2cap_input(
const std::uint8_t*, std::size_t, std::uint8_t* output, std::size_t& out_size, Connection& )
1281 error_response( details::sm_error_codes::pairing_not_supported, output, out_size );
1284 template <
typename SecurityFunctions,
typename ...Os >
1285 template <
class Connection >
1286 void no_security_manager::impl< SecurityFunctions, Os... >::l2cap_output( std::uint8_t*, std::size_t& out_size, Connection& )
A Security manager implementation that supports legacy pairing.
Definition: security_manager.hpp:451
A Security manager that implements only LESC pairing.
Definition: security_manager.hpp:482
const_iterator begin() const
returns an iterator to the first byte (LSB) of the address
const_iterator end() const
returns an iterator one behind the last byte of the address
data type containing a device address and the address type (public or random).
Definition: address.hpp:107
bool is_random() const
returns true, if this device address is a random device address.
Definition: address.hpp:114
implementation of the security manager, that actievly rejects every pairing attempt.
Definition: security_manager.hpp:533
A security manager that implpementes the full set of pairing methods (Legacy and LESC)
Definition: security_manager.hpp:510
access to a user defined key data base
Definition: security_manager.hpp:92
requests bonding during pairing
Definition: security_manager.hpp:577
set the MITM flag in the Authentication requirements flags of the pairing response.
Definition: security_manager.hpp:607
set the MITM flag in the Authentication requirements flags of the pairing response.
Definition: security_manager.hpp:592