BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
security_connection_data.hpp
1#ifndef BLUETOE_SM_SECURITY_CONNECTION_DATA_HPP
2#define BLUETOE_SM_SECURITY_CONNECTION_DATA_HPP
3
4namespace bluetoe {
5
6 namespace details {
7
8 using identity_resolving_key_t = std::array< std::uint8_t, 16 >;
9 using uint128_t = std::array< std::uint8_t, 16 >;
10
11 using ecdh_public_key_t = std::array< std::uint8_t, 64 >;
12 using ecdh_private_key_t = std::array< std::uint8_t, 32 >;
13 using ecdh_shared_secret_t = std::array< std::uint8_t, 32 >;
14
15 using io_capabilities_t = std::array< std::uint8_t, 3 >;
16
21 struct longterm_key_t
22 {
23 std::array< std::uint8_t, 16 > longterm_key;
24 std::uint64_t rand;
25 std::uint16_t ediv;
26
27 bool operator==(const longterm_key_t& rhs) const
28 {
29 return longterm_key == rhs.longterm_key
30 && rand == rhs.rand
31 && ediv == rhs.ediv;
32 }
33
34 bool operator!=(const longterm_key_t& rhs) const
35 {
36 return !(*this == rhs);
37 }
38 };
39
40 struct security_manager_meta_type {};
41 struct authentication_requirements_flags_meta_type {};
42 struct bonding_data_base_meta_type {};
43 struct key_distribution_meta_type {};
44
45 enum class sm_pairing_state : std::uint8_t {
46 // both, legacy and LESC
47 idle,
48 pairing_completed,
49 user_response_wait,
50 user_response_failed,
51 user_response_success,
52 // legacy only
53 legacy_pairing_requested,
54 legacy_pairing_confirmed,
55 // LESC only
56 lesc_pairing_requested,
57 lesc_public_keys_exchanged,
58 lesc_pairing_confirm_send,
59 lesc_pairing_random_exchanged,
60 };
61
62 enum class authentication_requirements_flags : std::uint8_t {
63 bonding = 0x01,
64 mitm = 0x04,
65 secure_connections = 0x08,
66 keypress = 0x10
67 };
68
69 template < class OtherConnectionData >
70 class security_connection_data_base : public OtherConnectionData
71 {
72 public:
73 template < class ... Args >
74 security_connection_data_base( Args&&... args )
75 : OtherConnectionData( args... )
76 , state_( details::sm_pairing_state::idle )
77 {}
78
79 details::sm_pairing_state state() const
80 {
81 return state_;
82 }
83
84 void remote_connection_created( const bluetoe::link_layer::device_address& remote )
85 {
86 remote_addr_ = remote;
87 }
88
89 const bluetoe::link_layer::device_address& remote_address() const
90 {
91 return remote_addr_;
92 }
93
94 void error_reset()
95 {
96 state( details::sm_pairing_state::idle );
97 }
98
99 protected:
100 void state( details::sm_pairing_state state )
101 {
102 state_ = state;
103 }
104
105 private:
106 link_layer::device_address remote_addr_;
107 details::sm_pairing_state state_;
108 };
109
110 template < class OtherConnectionData >
111 class legacy_security_connection_data : public security_connection_data_base< OtherConnectionData >
112 {
113 public:
114 template < class ... Args >
115 legacy_security_connection_data( Args&&... args )
116 : security_connection_data_base< OtherConnectionData >( args... )
117 {}
118
119 void legacy_pairing_request( const details::uint128_t& srand, const details::uint128_t& p1, const details::uint128_t& p2 )
120 {
121 assert( this->state() == details::sm_pairing_state::idle );
122 this->state( details::sm_pairing_state::legacy_pairing_requested );
123 state_data_.pairing_state.c1_p1 = p1;
124 state_data_.pairing_state.c1_p2 = p2;
125 state_data_.pairing_state.srand = srand;
126 }
127
128 void pairing_confirm( const std::uint8_t* mconfirm_begin, const std::uint8_t* mconfirm_end )
129 {
130 assert( this->state() == details::sm_pairing_state::legacy_pairing_requested );
131 this->state( details::sm_pairing_state::legacy_pairing_confirmed );
132
133 assert( static_cast< std::size_t >( mconfirm_end - mconfirm_begin ) == state_data_.pairing_state.mconfirm.max_size() );
134 std::copy( mconfirm_begin, mconfirm_end, state_data_.pairing_state.mconfirm.begin() );
135 }
136
137 void legacy_pairing_completed( const details::uint128_t& short_term_key )
138 {
139 assert( this->state() == details::sm_pairing_state::legacy_pairing_confirmed );
140 this->state( details::sm_pairing_state::pairing_completed );
141
142 state_data_.completed_state.short_term_key = short_term_key;
143 }
144
145 template < class Link >
146 bool outgoing_security_manager_data_available( const Link& link ) const
147 {
148 return link.is_encrypted() && this->state() != details::sm_pairing_state::pairing_completed;
149 }
150
151 std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const
152 {
153 if ( ediv == 0 && rand == 0 && this->state() == details::sm_pairing_state::pairing_completed )
154 return { true, state_data_.completed_state.short_term_key };
155
156 return std::pair< bool, details::uint128_t >{};
157 }
158
159 const details::uint128_t& c1_p1() const
160 {
161 return state_data_.pairing_state.c1_p1;
162 }
163
164 const details::uint128_t& c1_p2() const
165 {
166 return state_data_.pairing_state.c1_p2;
167 }
168
169 const details::uint128_t& srand() const
170 {
171 return state_data_.pairing_state.srand;
172 }
173
174 const details::uint128_t& mconfirm() const
175 {
176 return state_data_.pairing_state.mconfirm;
177 }
178
179 void pairing_algorithm( details::legacy_pairing_algorithm algo )
180 {
181 algorithm_ = algo;
182 }
183
184 details::legacy_pairing_algorithm legacy_pairing_algorithm() const
185 {
186 return algorithm_;
187 }
188
189 device_pairing_status local_device_pairing_status() const
190 {
191 if ( this->state() != details::sm_pairing_state::pairing_completed )
192 return bluetoe::device_pairing_status::no_key;
193
194 return algorithm_ == details::legacy_pairing_algorithm::just_works
195 ? device_pairing_status::unauthenticated_key
196 : device_pairing_status::authenticated_key;
197 }
198
199 void passkey( const details::uint128_t& key )
200 {
201 state_data_.pairing_state.passkey = key;
202 }
203
204 details::uint128_t passkey() const
205 {
206 return state_data_.pairing_state.passkey;
207 }
208 private:
209 details::legacy_pairing_algorithm algorithm_;
210
211 union {
212 struct {
213 details::uint128_t c1_p1;
214 details::uint128_t c1_p2;
215 details::uint128_t srand;
216 details::uint128_t mconfirm;
217 details::uint128_t passkey;
218 } pairing_state;
219
220 struct {
221 details::uint128_t short_term_key;
222 } completed_state;
223 } state_data_;
224 };
225
226 template < class OtherConnectionData >
227 class lesc_security_connection_data : public security_connection_data_base< OtherConnectionData >, public pairing_yes_no_response
228 {
229 public:
230 template < class ... Args >
231 lesc_security_connection_data( Args&&... args )
232 : security_connection_data_base< OtherConnectionData >( args... )
233 {}
234
235 void wait_for_user_response()
236 {
237 this->state( details::sm_pairing_state::user_response_wait );
238 }
239
240 void yes_no_response( bool response ) override
241 {
242 assert( this->state() == details::sm_pairing_state::user_response_wait );
243
244 this->state( response
245 ? details::sm_pairing_state::user_response_success
246 : details::sm_pairing_state::user_response_failed );
247 }
248
249 device_pairing_status local_device_pairing_status() const
250 {
251 return this->state() == details::sm_pairing_state::pairing_completed
252 ? bluetoe::device_pairing_status::unauthenticated_key
253 : bluetoe::device_pairing_status::no_key;
254 }
255
256 std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const
257 {
258 if ( this->state() == details::sm_pairing_state::pairing_completed && ediv == 0 && rand == 0 )
259 return { true, long_term_key_ };
260
261 return std::pair< bool, details::uint128_t >{};
262 }
263
264 void pairing_requested( const io_capabilities_t& remote_io_caps )
265 {
266 assert( this->state() == details::sm_pairing_state::idle );
267 this->state( details::sm_pairing_state::lesc_pairing_requested );
268 remote_io_caps_ = remote_io_caps;
269 }
270
271 void public_key_exchanged(
272 const ecdh_private_key_t& local_private_key,
273 const ecdh_public_key_t& local_public_key,
274 const std::uint8_t* remote_public_key,
275 const details::uint128_t& nonce )
276 {
277 assert( this->state() == details::sm_pairing_state::lesc_pairing_requested );
278 this->state( details::sm_pairing_state::lesc_public_keys_exchanged );
279
280 local_private_key_ = local_private_key;
281 local_public_key_ = local_public_key;
282 local_nonce_ = nonce;
283 std::copy( remote_public_key, remote_public_key + remote_public_key_.size(), remote_public_key_.begin() );
284 }
285
286 void pairing_confirm_send()
287 {
288 assert( this->state() == details::sm_pairing_state::lesc_public_keys_exchanged );
289 this->state( details::sm_pairing_state::lesc_pairing_confirm_send );
290 }
291
292 void pairing_random_exchanged( const std::uint8_t* remote_nonce )
293 {
294 assert( this->state() == details::sm_pairing_state::lesc_pairing_confirm_send );
295 this->state( details::sm_pairing_state::lesc_pairing_random_exchanged );
296
297 std::copy( remote_nonce, remote_nonce + 16, remote_nonce_.begin() );
298 }
299
300 void lesc_pairing_completed( const details::uint128_t& long_term_key )
301 {
302 assert( this->state() == details::sm_pairing_state::lesc_pairing_random_exchanged
303 || this->state() == details::sm_pairing_state::user_response_success );
304
305 this->state( details::sm_pairing_state::pairing_completed );
306
307 long_term_key_ = long_term_key;
308 }
309
310 const uint128_t& local_nonce() const
311 {
312 return local_nonce_;
313 }
314
315 const uint128_t& remote_nonce() const
316 {
317 return remote_nonce_;
318 }
319
320 const std::uint8_t* local_public_key_x() const
321 {
322 return local_public_key_.data();
323 }
324
325 const std::uint8_t* remote_public_key_x() const
326 {
327 return remote_public_key_.data();
328 }
329
330 const std::uint8_t* remote_public_key() const
331 {
332 return remote_public_key_.data();
333 }
334
335 const std::uint8_t* local_private_key() const
336 {
337 return local_private_key_.data();
338 }
339
340 const io_capabilities_t& remote_io_caps() const
341 {
342 return remote_io_caps_;
343 }
344
345 void pairing_algorithm( details::lesc_pairing_algorithm algo )
346 {
347 algorithm_ = algo;
348 }
349
350 details::lesc_pairing_algorithm lesc_pairing_algorithm() const
351 {
352 return algorithm_;
353 }
354 private:
355 enum lesc_pairing_algorithm algorithm_;
356
357 ecdh_private_key_t local_private_key_;
358 ecdh_public_key_t local_public_key_;
359 ecdh_public_key_t remote_public_key_;
360 uint128_t local_nonce_;
361 uint128_t remote_nonce_;
362 io_capabilities_t remote_io_caps_;
363 uint128_t long_term_key_;
364 };
365
366 template < class OtherConnectionData >
367 class security_connection_data : public security_connection_data_base< OtherConnectionData >, public pairing_yes_no_response
368 {
369 public:
370 template < class ... Args >
371 security_connection_data( Args&&... args )
372 : security_connection_data_base< OtherConnectionData >( args... )
373 {}
374
375 void wait_for_user_response()
376 {
377 this->state( details::sm_pairing_state::user_response_wait );
378 }
379
380 void yes_no_response( bool response ) override
381 {
382 assert( this->state() == details::sm_pairing_state::user_response_wait );
383
384 this->state( response
385 ? details::sm_pairing_state::user_response_success
386 : details::sm_pairing_state::user_response_failed );
387 }
388
389 void pairing_algorithm( details::legacy_pairing_algorithm algo )
390 {
391 state_data_.legacy_state.algorithm = algo;
392 }
393
394 details::legacy_pairing_algorithm legacy_pairing_algorithm() const
395 {
396 return state_data_.legacy_state.algorithm;
397 }
398
399 void pairing_algorithm( details::lesc_pairing_algorithm algo )
400 {
401 state_data_.lesc_state.algorithm = algo;
402 }
403
404 details::lesc_pairing_algorithm lesc_pairing_algorithm() const
405 {
406 return state_data_.lesc_state.algorithm;
407 }
408
409 void legacy_pairing_request( const details::uint128_t& srand, const details::uint128_t& p1, const details::uint128_t& p2 )
410 {
411 assert( this->state() == details::sm_pairing_state::idle );
412 this->state( details::sm_pairing_state::legacy_pairing_requested );
413 state_data_.legacy_state.states.pairing_state.c1_p1 = p1;
414 state_data_.legacy_state.states.pairing_state.c1_p2 = p2;
415 state_data_.legacy_state.states.pairing_state.srand = srand;
416 }
417
418 void pairing_confirm( const std::uint8_t* mconfirm_begin, const std::uint8_t* mconfirm_end )
419 {
420 assert( this->state() == details::sm_pairing_state::legacy_pairing_requested );
421 this->state( details::sm_pairing_state::legacy_pairing_confirmed );
422
423 assert( static_cast< std::size_t >( mconfirm_end - mconfirm_begin ) == state_data_.legacy_state.states.pairing_state.mconfirm.max_size() );
424 std::copy( mconfirm_begin, mconfirm_end, state_data_.legacy_state.states.pairing_state.mconfirm.begin() );
425 }
426
427 void legacy_pairing_completed( const details::uint128_t& short_term_key )
428 {
429 assert( this->state() == details::sm_pairing_state::legacy_pairing_confirmed );
430 this->state( details::sm_pairing_state::pairing_completed );
431
432 long_term_key_ = short_term_key;
433
434 pairing_status_ = state_data_.legacy_state.algorithm == details::legacy_pairing_algorithm::just_works
435 ? device_pairing_status::unauthenticated_key
436 : device_pairing_status::authenticated_key;
437 }
438
439 void lesc_pairing_completed( const details::uint128_t& long_term_key )
440 {
441 assert( this->state() == details::sm_pairing_state::lesc_pairing_random_exchanged
442 || this->state() == details::sm_pairing_state::user_response_success );
443
444 this->state( details::sm_pairing_state::pairing_completed );
445
446 long_term_key_ = long_term_key;
447
448 pairing_status_ = state_data_.lesc_state.algorithm == details::lesc_pairing_algorithm::just_works
449 ? device_pairing_status::unauthenticated_key
450 : device_pairing_status::authenticated_key;
451 }
452
453 const details::uint128_t& c1_p1() const
454 {
455 return state_data_.legacy_state.states.pairing_state.c1_p1;
456 }
457
458 const details::uint128_t& c1_p2() const
459 {
460 return state_data_.legacy_state.states.pairing_state.c1_p2;
461 }
462
463 const details::uint128_t& srand() const
464 {
465 return state_data_.legacy_state.states.pairing_state.srand;
466 }
467
468 const details::uint128_t& mconfirm() const
469 {
470 return state_data_.legacy_state.states.pairing_state.mconfirm;
471 }
472
473 void passkey( const details::uint128_t& key )
474 {
475 state_data_.legacy_state.states.pairing_state.passkey = key;
476 }
477
478 details::uint128_t passkey() const
479 {
480 return state_data_.legacy_state.states.pairing_state.passkey;
481 }
482
483 void public_key_exchanged(
484 const ecdh_private_key_t& local_private_key,
485 const ecdh_public_key_t& local_public_key,
486 const std::uint8_t* remote_public_key,
487 const details::uint128_t& nonce )
488 {
489 assert( this->state() == details::sm_pairing_state::lesc_pairing_requested );
490 this->state( details::sm_pairing_state::lesc_public_keys_exchanged );
491
492 state_data_.lesc_state.local_private_key_ = local_private_key;
493 state_data_.lesc_state.local_public_key_ = local_public_key;
494 state_data_.lesc_state.local_nonce_ = nonce;
495 std::copy( remote_public_key, remote_public_key + state_data_.lesc_state.remote_public_key_.size(), state_data_.lesc_state.remote_public_key_.begin() );
496 }
497
498 void pairing_confirm_send()
499 {
500 assert( this->state() == details::sm_pairing_state::lesc_public_keys_exchanged );
501 this->state( details::sm_pairing_state::lesc_pairing_confirm_send );
502 }
503
504 void pairing_random_exchanged( const std::uint8_t* remote_nonce )
505 {
506 assert( this->state() == details::sm_pairing_state::lesc_pairing_confirm_send );
507 this->state( details::sm_pairing_state::lesc_pairing_random_exchanged );
508
509 std::copy( remote_nonce, remote_nonce + 16, state_data_.lesc_state.remote_nonce_.begin() );
510 }
511
512 void pairing_requested( const io_capabilities_t& remote_io_caps )
513 {
514 assert( this->state() == details::sm_pairing_state::idle );
515 this->state( details::sm_pairing_state::lesc_pairing_requested );
516 state_data_.lesc_state.remote_io_caps_ = remote_io_caps;
517 }
518
519 const uint128_t& local_nonce() const
520 {
521 return state_data_.lesc_state.local_nonce_;
522 }
523
524 const uint128_t& remote_nonce() const
525 {
526 return state_data_.lesc_state.remote_nonce_;
527 }
528
529 const std::uint8_t* local_public_key_x() const
530 {
531 return state_data_.lesc_state.local_public_key_.data();
532 }
533
534 const std::uint8_t* remote_public_key_x() const
535 {
536 return state_data_.lesc_state.remote_public_key_.data();
537 }
538
539 const std::uint8_t* remote_public_key() const
540 {
541 return state_data_.lesc_state.remote_public_key_.data();
542 }
543
544 const std::uint8_t* local_private_key() const
545 {
546 return state_data_.lesc_state.local_private_key_.data();
547 }
548
549 const io_capabilities_t& remote_io_caps() const
550 {
551 return state_data_.lesc_state.remote_io_caps_;
552 }
553
554 template < class Link >
555 bool outgoing_security_manager_data_available( const Link& link ) const
556 {
557 return link.is_encrypted() && this->state() != details::sm_pairing_state::pairing_completed;
558 }
559
560 std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const
561 {
562 if ( this->state() == details::sm_pairing_state::pairing_completed && ediv == 0 && rand == 0 )
563 return { true, long_term_key_ };
564
565 return std::pair< bool, details::uint128_t >{};
566 }
567
568 device_pairing_status local_device_pairing_status() const
569 {
570 if ( this->state() != details::sm_pairing_state::pairing_completed )
571 return bluetoe::device_pairing_status::no_key;
572
573 return pairing_status_;
574 }
575
576 private:
577 details::uint128_t long_term_key_;
578 device_pairing_status pairing_status_;
579
580 union {
581 struct {
582 union {
583 struct {
584 details::uint128_t c1_p1;
585 details::uint128_t c1_p2;
586 details::uint128_t srand;
587 details::uint128_t mconfirm;
588 details::uint128_t passkey;
589 } pairing_state;
590 } states;
591 enum legacy_pairing_algorithm algorithm;
592 } legacy_state;
593
594 struct {
595 ecdh_private_key_t local_private_key_;
596 ecdh_public_key_t local_public_key_;
597 ecdh_public_key_t remote_public_key_;
598 uint128_t local_nonce_;
599 uint128_t remote_nonce_;
600 io_capabilities_t remote_io_caps_;
601 enum lesc_pairing_algorithm algorithm;
602 } lesc_state;
603 } state_data_;
604 };
605 }
606}
607
608#endif