BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
security_manager.hpp
1#ifndef BLUETOE_SM_SECURITY_MANAGER_HPP
2#define BLUETOE_SM_SECURITY_MANAGER_HPP
3
4#include <cstddef>
5#include <cstdint>
6#include <cassert>
7#include <array>
8#include <algorithm>
9
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>
20
21namespace bluetoe {
22
23 namespace details {
24
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
40 };
41
42 enum class sm_opcodes : std::uint8_t {
43 pairing_request = 0x01,
44 pairing_response,
45 pairing_confirm,
46 pairing_random,
47 pairing_failed,
48 encryption_information,
49 central_identification,
50 identity_information,
51 identity_address_information,
52 signing_information,
53 security_request,
54 pairing_public_key,
55 pairing_dhkey_check,
56 pairing_keypress_notification
57 };
58 }
59
90 template < class Obj, Obj& obj >
92 {
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 {};
98
99 static constexpr std::uint8_t flags = static_cast< std::uint8_t >(
100 details::authentication_requirements_flags::bonding );
101
102 // Data that has to be added by the bonding data base
103 template < class OtherConnectionData >
104 class bonding_db_data_t : public OtherConnectionData
105 {
106 public:
107 std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const
108 {
109 const auto local_key = OtherConnectionData::find_key( ediv, rand );
110
111 if ( local_key.first )
112 return local_key;
113
114 return obj.find_key( ediv, rand, this->remote_address() );
115 }
116
117 template < class Radio, class Connection >
118 void arm_key_distribution( Radio& radio, const Connection& connection )
119 {
120 pending_encryption_information = true;
121 pending_central_identification = true;
122
123 pending_key = obj.create_new_bond( radio, connection.remote_address() );
124 obj.store_bond( pending_key, connection );
125 }
126
127 template < typename Connection >
128 void store_lesc_key_in_bond_db( const details::uint128_t& key, const Connection& connection )
129 {
130 obj.store_bond( details::longterm_key_t{ key, 0u, 0u }, connection );
131 }
132
133 template < typename Connection >
134 void distribute_keys( std::uint8_t* output, std::size_t& out_size, Connection& connection )
135 {
136 out_size = 0;
137
138 if ( connection.security_attributes().is_encrypted )
139 {
140 if ( pending_encryption_information )
141 {
142 pending_encryption_information = false;
143
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 );
147
148 out_size = 17;
149 }
150 else if ( pending_central_identification )
151 {
152 pending_central_identification = false;
153
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 );
157
158 out_size = 11;
159 }
160 }
161 }
162
163 template < typename Connection >
164 void restore_bonded_cccds( Connection& connection )
165 {
166 obj.restore_cccds( connection );
167 }
168
169 private:
170 bool pending_encryption_information;
171 bool pending_central_identification;
172 details::longterm_key_t pending_key;
173 };
174
175 static constexpr std::uint8_t request_key_flags = 0x01;
176
178 };
179
181 struct no_bonding_data_base
182 {
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 {};
186
187 template < class OtherConnectionData >
188 struct bonding_db_data_t : OtherConnectionData
189 {
190 template < class Radio, class Connection >
191 void arm_key_distribution( Radio&, const Connection& )
192 {
193 }
194
195 template < typename Connection >
196 void distribute_keys( std::uint8_t*, std::size_t& out_size, Connection& )
197 {
198 out_size = 0;
199 }
200
201 template < typename Connection >
202 void store_lesc_key_in_bond_db( const details::uint128_t&, const Connection& )
203 {
204 }
205
206 template < typename Connection >
207 void restore_bonded_cccds( Connection& )
208 {
209 }
210 };
211
212 };
213
214 struct no_key_distribution
215 {
216 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
217 details::key_distribution_meta_type {};
218
219 static constexpr std::uint8_t request_key_flags = 0;
220 };
223 namespace details {
224
225 inline void error_response( details::sm_error_codes error_code, std::uint8_t* output, std::size_t& out_size )
226 {
227 output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_failed );
228 output[ 1 ] = static_cast< std::uint8_t >( error_code );
229
230 out_size = 2;
231 }
232
233 template < typename ... Options >
234 struct accumulate_authentication_requirements_flags;
235
236 template <>
237 struct accumulate_authentication_requirements_flags< std::tuple<> >
238 {
239 static constexpr std::uint8_t flags = 0;
240 };
241
242 template < typename Option, class ... Options >
243 struct accumulate_authentication_requirements_flags< std::tuple< Option, Options... > > :
244 accumulate_authentication_requirements_flags< std::tuple< Options... > >
245 {
246 static constexpr std::uint8_t flags = Option::flags
247 | accumulate_authentication_requirements_flags< std::tuple< Options... > >::flags;
248 };
249
250 // features required by legacy and by lesc pairing
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,
255 Options...,
256 details::no_oob_authentication >::type
257 {
258 protected:
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
262 >::flags;
263
264 using bonding_data_base_t = typename details::find_by_meta_type<
265 details::bonding_data_base_meta_type,
266 Options...,
267 no_bonding_data_base >::type;
268
269 using key_distribution_t = typename details::find_by_meta_type<
270 details::key_distribution_meta_type,
271 Options...,
272 no_key_distribution >::type;
273
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 )
276 {
277 state.error_reset();
278 details::error_response( error_code, output, out_size );
279 }
280
281 using io_device_t = io_capabilities_matrix< Options... >;
282
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;
286
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& );
289
290 void create_pairing_response( std::uint8_t* output, std::size_t& out_size, const io_capabilities_t& io_caps );
291
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& );
294
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& );
297
298 template < class Connection >
299 uint128_t legacy_create_temporary_key( Connection& );
300
301 template < class Connection >
302 uint128_t legacy_temporary_key( const Connection& ) const;
303
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 );
305
306 details::uint128_t legacy_c1_p1(
307 const std::uint8_t* input, const std::uint8_t* output,
308 const bluetoe::link_layer::device_address& initiating_device,
309 const bluetoe::link_layer::device_address& responding_device );
310
311 details::uint128_t legacy_c1_p2(
312 const bluetoe::link_layer::device_address& initiating_device,
313 const bluetoe::link_layer::device_address& responding_device );
314
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;
319
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& );
322
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& );
325
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& );
328
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& );
331
332 template < class Connection >
333 bool lesc_security_manager_output_available( Connection& ) const;
334
335 template < class Connection >
336 void lesc_l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
337
338 details::io_capabilities_t legacy_local_io_caps() const;
339 details::io_capabilities_t lesc_local_io_caps() const;
340
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 );
342
343 SecurityFunctions& security_functions()
344 {
345 return static_cast< SecurityFunctions& >( *this );
346 }
347
348 const SecurityFunctions& security_functions() const
349 {
350 return static_cast< const SecurityFunctions& >( *this );
351 }
352 };
353
354 template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >
355 class legacy_security_manager_impl : public security_manager_base< SecurityFunctions, ConnectionData, Options... >
356 {
357 public:
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& );
362
363 template < class Connection >
364 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
365
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;
369
370 using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;
371
372 template < class OtherConnectionData >
373 using channel_data_t = typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;
375 };
376
377 template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >
378 class lesc_security_manager_impl : public security_manager_base< SecurityFunctions, ConnectionData, Options... >
379 {
380 public:
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& );
384
385 template < class Connection >
386 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
387
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;
391
392 using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;
393
394 template < class OtherConnectionData >
395 using channel_data_t = typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;
397 };
398
399 template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >
400 class security_manager_impl : public security_manager_base< SecurityFunctions, ConnectionData, Options... >
401 {
402 public:
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& );
406
407 template < class Connection >
408 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
409
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;
413
414 using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;
415
416 template < class OtherConnectionData >
417 using channel_data_t = typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;
418
419 private:
420 using security_manager_base< SecurityFunctions, ConnectionData, Options... >::security_functions;
421
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& );
424
426 };
427
428 } // namespace details
429
451 {
452 public:
454 template < typename SecurityFunctions, typename ... Options >
455 using impl = details::legacy_security_manager_impl< SecurityFunctions, details::legacy_security_connection_data, Options... >;
456
457 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
458 details::security_manager_meta_type {};
460 };
461
482 {
483 public:
485 template < typename SecurityFunctions, typename ... Options >
486 using impl = details::lesc_security_manager_impl< SecurityFunctions, details::lesc_security_connection_data, Options... >;
487
488 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
489 details::security_manager_meta_type {};
491 };
492
510 {
511 public:
513 template < typename SecurityFunctions, typename ... Options >
514 using impl = details::security_manager_impl< SecurityFunctions, details::security_connection_data, Options... >;
515
516 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
517 details::security_manager_meta_type {};
518
520 };
521
533 {
534 public:
536 template < typename SecurityFunctions, typename ... >
537 class impl
538 {
539 public:
540 template < class OtherConnectionData >
541 class channel_data_t : public OtherConnectionData
542 {
543 public:
544 void remote_connection_created( const bluetoe::link_layer::device_address& )
545 {
546 }
547
548 device_pairing_status local_device_pairing_status() const
549 {
550 return bluetoe::device_pairing_status::no_key;
551 }
552
553 };
554
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& );
557
558 template < class Connection >
559 void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );
560
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;
564 };
565
566 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
567 details::security_manager_meta_type {};
569 };
570
577 {
579 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
580 details::authentication_requirements_flags_meta_type {};
581
582 static constexpr std::uint8_t flags = static_cast< std::uint8_t >(
583 details::authentication_requirements_flags::bonding );
585 };
586
592 {
594 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
595 details::authentication_requirements_flags_meta_type {};
596
597 static constexpr std::uint8_t flags = static_cast< std::uint8_t >(
598 details::authentication_requirements_flags::mitm );
600 };
601
607 {
609 struct meta_type : link_layer::details::valid_link_layer_option_meta_type,
610 details::authentication_requirements_flags_meta_type {};
611
612 static constexpr std::uint8_t flags = static_cast< std::uint8_t >(
613 details::authentication_requirements_flags::keypress );
615 };
616
617 /*
618 * Implementation
619 */
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 )
625 {
626 using namespace details;
627
628 if ( in_size != pairing_req_resp_size )
629 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
630
631 if ( state.state() != details::sm_pairing_state::idle )
632 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
633
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 ];
640
641 if (
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 )
647 )
648 {
649 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
650 }
651
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() ) );
654
655 create_pairing_response( output, out_size, legacy_local_io_caps() );
656
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() );
660
661 state.legacy_pairing_request( srand, p1, p2 );
662 }
663
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 )
666 {
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;
673 output[ 5 ] = 0;
674 output[ 6 ] = key_distribution_t::request_key_flags;
675 }
676
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 )
681 {
682 using namespace details;
683
684 static constexpr std::size_t request_size = 17;
685
686 if ( in_size != request_size )
687 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
688
689 if ( state.state() != sm_pairing_state::legacy_pairing_requested )
690 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
691
692 // save mconfirm for later
693 state.pairing_confirm( &input[ 1 ], &input[ request_size ] );
694
695 out_size = request_size;
696 output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_confirm );
697
698 const auto temp_key = legacy_create_temporary_key( state );
699
700 io_device_t::sm_pairing_numeric_output( temp_key );
701
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 ] );
704 }
705
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 )
710 {
711 using namespace details;
712
713 static constexpr std::size_t pairing_random_size = 17;
714
715 if ( in_size != pairing_random_size )
716 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
717
718 if ( state.state() != sm_pairing_state::legacy_pairing_confirmed )
719 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
720
721 uint128_t mrand;
722 std::copy( &input[ 1 ], &input[ pairing_random_size ], mrand.begin() );
723 const uint128_t temp_key = legacy_temporary_key( state );
724
725 const auto mconfirm = security_functions().c1( temp_key, mrand, state.c1_p1(), state.c1_p2() );
726
727 if ( mconfirm != state.mconfirm() )
728 return this->error_response( sm_error_codes::confirm_value_failed, output, out_size, state );
729
730 out_size = pairing_random_size;
731 output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_random );
732
733 const auto srand = state.srand();
734 std::copy( srand.begin(), srand.end(), &output[ 1 ] );
735
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 );
739 }
740
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 )
744 {
745 const auto algo = state.legacy_pairing_algorithm();
746
747 switch ( algo )
748 {
749 case legacy_pairing_algorithm::oob_authentication:
750 return this->get_oob_data_for_last_remote_device();
751
752 case legacy_pairing_algorithm::passkey_entry_display:
753 {
754 const auto key = security_functions().create_passkey();
755 state.passkey( key );
756
757 return key;
758 }
759
760 case legacy_pairing_algorithm::passkey_entry_input:
761 {
762
763 const auto key = io_device_t::sm_pairing_passkey();
764 state.passkey( key );
765
766 return key;
767 }
768
769 default:
770 break;
771 }
772
773 return uint128_t( { 0 } );
774 }
775
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
779 {
780 const auto algo = state.legacy_pairing_algorithm();
781
782 switch ( algo )
783 {
784 case legacy_pairing_algorithm::oob_authentication:
785 return this->get_oob_data_for_last_remote_device();
786
787 case legacy_pairing_algorithm::passkey_entry_display:
788 case legacy_pairing_algorithm::passkey_entry_input:
789 return state.passkey();
790
791 default:
792 break;
793 }
794
795 return uint128_t( { 0 } );
796 }
797
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 /* auth_req */, bool has_oob_data )
800 {
801 if ( oob_data_flag && has_oob_data )
802 return details::legacy_pairing_algorithm::oob_authentication;
803
804 return io_device_t::select_legacy_pairing_algorithm( io_capability );
805 }
806
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,
810 const bluetoe::link_layer::device_address& initiating_device,
811 const bluetoe::link_layer::device_address& responding_device )
812 {
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 ) } };
816
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 ] );
819
820 return result;
821 }
822
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(
825 const bluetoe::link_layer::device_address& initiating_device,
826 const bluetoe::link_layer::device_address& responding_device )
827 {
828 static constexpr std::size_t address_size_in_bytes = 6;
829 static constexpr std::uint8_t padding = 0;
830
831 details::uint128_t result;
832
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 );
836
837 return result;
838 }
839
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 )
844 {
845 using namespace details;
846
847 if ( in_size != pairing_req_resp_size )
848 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
849
850 if ( state.state() != details::sm_pairing_state::idle )
851 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
852
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 ];
859
860 if (
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 )
866 )
867 {
868 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
869 }
870
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 );
873
874 const io_capabilities_t remote_io_caps = {{ io_capability, oob_data_flag, auth_req }};
875
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() );
879 }
880
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
883 {
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;
886
887 return {{
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 }};
893 }
894
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
897 {
898 return {{
899 static_cast< std::uint8_t >( io_device_t::get_io_capabilities() ),
900 0,
901 authentication_requirements_flags | static_cast< std::uint8_t >( details::authentication_requirements_flags::secure_connections ) }};
902 }
903
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 )
908 {
909 if ( in_size != public_key_exchange_size )
910 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
911
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 );
914
915 assert( out_size >= public_key_exchange_size );
916
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 );
919
920 output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::pairing_public_key );
921
922 out_size = public_key_exchange_size;
923 const auto& keys = security_functions().generate_keys();
924 const auto& nonce = security_functions().select_random_nonce();
925
926 state.public_key_exchanged( keys.second, keys.first, &input[ 1 ], nonce );
927 std::copy( keys.first.begin(), keys.first.end(), &output[ 1 ] );
928 }
929
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 )
933 {
934 if ( in_size != pairing_random_size )
935 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
936
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 );
939
940 state.pairing_random_exchanged( input + 1 );
941
942 if ( state.lesc_pairing_algorithm() == lesc_pairing_algorithm::numeric_comparison )
943 {
944 io_device_t::sm_pairing_numeric_compare_output( state, security_functions() );
945 io_device_t::sm_pairing_request_yes_no( state );
946 }
947
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 );
950
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 ] );
955 }
956
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 )
960 {
961 if ( in_size != pairing_dhkey_check_size )
962 return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );
963
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
969 };
970
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 );
973
974 if ( state.state() == details::sm_pairing_state::user_response_wait )
975 {
976 out_size = 0;
977 }
978 else if ( state.state() == details::sm_pairing_state::user_response_failed )
979 {
980 return this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );
981 }
982 else
983 {
984 const details::ecdh_shared_secret_t dh_key = security_functions().p256( state.local_private_key(), state.remote_public_key() );
985
986 details::uint128_t mac_key;
987 details::uint128_t ltk;
988 static const details::uint128_t zero = {{ 0 }};
989
990 std::tie( mac_key, ltk ) = security_functions().f5( dh_key, state.remote_nonce(), state.local_nonce(), state.remote_address(), security_functions().local_address() );
991
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() );
993
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 );
996
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() );
998
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 ] );
1002
1003 state.lesc_pairing_completed( ltk );
1004 state.store_lesc_key_in_bond_db( ltk, state );
1005 }
1006 }
1007
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
1011 {
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;
1015 }
1016
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 )
1020 {
1021 assert( lesc_security_manager_output_available( state ) );
1022
1023 if ( state.state() == details::sm_pairing_state::lesc_public_keys_exchanged )
1024 {
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();
1028
1029 const auto confirm = security_functions().f4( PKbx, Pkax, Nb, 0 );
1030
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 ] );
1034
1035 state.pairing_confirm_send();
1036 }
1037 else if ( state.state() == details::sm_pairing_state::user_response_success )
1038 {
1039 const details::ecdh_shared_secret_t dh_key = security_functions().p256( state.local_private_key(), state.remote_public_key() );
1040
1041 details::uint128_t mac_key;
1042 details::uint128_t ltk;
1043 static const details::uint128_t zero = {{ 0 }};
1044
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() );
1047
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 ] );
1051
1052 state.lesc_pairing_completed( ltk );
1053 state.store_lesc_key_in_bond_db( ltk, state );
1054 }
1055 else
1056 {
1057 this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );
1058 }
1059
1060 }
1061
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 /* auth_req */, bool has_oob_data )
1064 {
1065 if ( oob_data_flag || has_oob_data )
1066 return details::lesc_pairing_algorithm::oob_authentication;
1067
1068 return io_device_t::select_lesc_pairing_algorithm( io_capability );
1069 }
1070
1071 // Legacy
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 )
1076 {
1077 using namespace bluetoe::details;
1078
1079 // is there at least an opcode?
1080 if ( in_size == 0 )
1081 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1082
1083 assert( in_size != 0 );
1084 assert( out_size >= default_att_mtu_size );
1085
1086 const sm_opcodes opcode = static_cast< sm_opcodes >( input[ 0 ] );
1087
1088 switch ( opcode )
1089 {
1090 case sm_opcodes::pairing_request:
1091 this->legacy_handle_pairing_request( input, in_size, output, out_size, state );
1092 break;
1093 case sm_opcodes::pairing_confirm:
1094 this->legacy_handle_pairing_confirm( input, in_size, output, out_size, state );
1095 break;
1096 case sm_opcodes::pairing_random:
1097 this->legacy_handle_pairing_random( input, in_size, output, out_size, state );
1098 break;
1099 default:
1100 this->error_response( sm_error_codes::command_not_supported, output, out_size, state );
1101 }
1102 }
1103
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 )
1107 {
1108 state.distribute_keys( output, out_size, state );
1109 }
1110
1111 // LESC
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 )
1116 {
1117 using namespace bluetoe::details;
1118
1119 // is there at least an opcode?
1120 if ( in_size == 0 )
1121 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1122
1123 assert( in_size != 0 );
1124 assert( out_size >= default_att_mtu_size );
1125
1126 const sm_opcodes opcode = static_cast< sm_opcodes >( input[ 0 ] );
1127
1128 switch ( opcode )
1129 {
1130 case sm_opcodes::pairing_request:
1131 this->lesc_handle_pairing_request( input, in_size, output, out_size, state );
1132 break;
1133 case sm_opcodes::pairing_public_key:
1134 this->lesc_handle_pairing_public_key( input, in_size, output, out_size, state );
1135 break;
1136 case sm_opcodes::pairing_random:
1137 this->lesc_handle_pairing_random( input, in_size, output, out_size, state );
1138 break;
1139 case sm_opcodes::pairing_dhkey_check:
1140 this->lesc_handle_pairing_dhkey_check( input, in_size, output, out_size, state );
1141 break;
1142 default:
1143 this->error_response( sm_error_codes::command_not_supported, output, out_size, state );
1144 }
1145 }
1146
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 )
1150 {
1151 if ( this->lesc_security_manager_output_available( state ) )
1152 {
1153 this->lesc_l2cap_output( output, out_size, state );
1154 }
1155 else
1156 {
1157 out_size = 0;
1158 }
1159 }
1160
1161 // security_manager_impl
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 )
1165 {
1166 using namespace bluetoe::details;
1167
1168 // is there at least an opcode?
1169 if ( in_size == 0 )
1170 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1171
1172 assert( in_size != 0 );
1173 assert( out_size >= default_att_mtu_size );
1174
1175 const sm_opcodes opcode = static_cast< sm_opcodes >( input[ 0 ] );
1176
1177 switch ( opcode )
1178 {
1179 case sm_opcodes::pairing_request:
1180 handle_pairing_request( input, in_size, output, out_size, state );
1181 break;
1182 case sm_opcodes::pairing_confirm:
1183 this->legacy_handle_pairing_confirm( input, in_size, output, out_size, state );
1184 break;
1185 case sm_opcodes::pairing_random:
1186 if ( state.state() == sm_pairing_state::legacy_pairing_confirmed )
1187 {
1188 this->legacy_handle_pairing_random( input, in_size, output, out_size, state );
1189 }
1190 else
1191 {
1192 this->lesc_handle_pairing_random( input, in_size, output, out_size, state );
1193 }
1194 break;
1195 case sm_opcodes::pairing_public_key:
1196 this->lesc_handle_pairing_public_key( input, in_size, output, out_size, state );
1197 break;
1198 case sm_opcodes::pairing_dhkey_check:
1199 this->lesc_handle_pairing_dhkey_check( input, in_size, output, out_size, state );
1200 break;
1201 default:
1202 this->error_response( sm_error_codes::command_not_supported, output, out_size, state );
1203 }
1204 }
1205
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 )
1209 {
1210 if ( this->lesc_security_manager_output_available( state ) )
1211 {
1212 this->lesc_l2cap_output( output, out_size, state );
1213 }
1214 else
1215 {
1216 state.distribute_keys( output, out_size, state );
1217 }
1218 }
1219
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 )
1223 {
1224 using namespace details;
1225
1226 if ( in_size != this->pairing_req_resp_size )
1227 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1228
1229 if ( state.state() != details::sm_pairing_state::idle )
1230 return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );
1231
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 ];
1238
1239 if (
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 )
1245 )
1246 {
1247 return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );
1248 }
1249
1250 this->request_oob_data_presents_for_remote_device( state.remote_address() );
1251
1252 const bool lesc_pairing = ( auth_req & static_cast< std::uint8_t >(authentication_requirements_flags::secure_connections ) );
1253
1254 if ( lesc_pairing )
1255 {
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 );
1259
1260 this->create_pairing_response( output, out_size, this->lesc_local_io_caps() );
1261 }
1262 else
1263 {
1264 state.pairing_algorithm( this->legacy_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );
1265
1266 this->create_pairing_response( output, out_size, this->lesc_local_io_caps() );
1267
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() );
1271
1272 state.legacy_pairing_request( srand, p1, p2 );
1273 }
1274 }
1275
1276 // no_security_manager
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& )
1280 {
1281 error_response( details::sm_error_codes::pairing_not_supported, output, out_size );
1282 }
1283
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& )
1287 {
1288 out_size = 0;
1289 }
1291}
1292
1293#endif // include guard
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
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