1#![warn(missing_docs)]
2mod constants;
6pub(crate) mod crypto;
7mod pairing;
8mod types;
9use core::cell::{Ref, RefCell};
10use core::future::{poll_fn, Future};
11use core::task::Poll;
12
13use bt_hci::event::le::{LeEventKind, LeEventPacket, LeLongTermKeyRequest};
14use bt_hci::event::{EncryptionChangeV1, EncryptionKeyRefreshComplete, EventKind, EventPacket};
15use bt_hci::param::{ConnHandle, EncryptionEnabledLevel, LeConnRole};
16use bt_hci::FromHciBytes;
17pub use crypto::{IdentityResolvingKey, LongTermKey};
18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
19use embassy_sync::channel::Channel;
20use embassy_sync::waitqueue::WakerRegistration;
21use embassy_time::{Instant, TimeoutError, WithTimeout};
22use heapless::VecView;
23pub use pairing::OobData;
24use rand_chacha::ChaCha12Rng;
25use rand_core::SeedableRng;
26use types::Command;
27pub use types::{PassKey, Reason};
28
29use crate::connection::SecurityLevel;
30use crate::connection_manager::{ConnectionManager, ConnectionStorage};
31use crate::pdu::Pdu;
32use crate::prelude::ConnectionEvent;
33use crate::security_manager::pairing::{Pairing, PairingOps};
34#[cfg(feature = "legacy-pairing")]
35use crate::security_manager::types::AuthReq;
36use crate::security_manager::types::BondingFlag;
37use crate::types::l2cap::L2CAP_CID_LE_U_SECURITY_MANAGER;
38use crate::{Address, Error, Identity, IoCapabilities, PacketPool};
39
40pub(crate) enum SecurityEventData {
42 SendLongTermKey(ConnHandle, u16, [u8; 8]),
44 EnableEncryption(ConnHandle, BondInformation),
46 Timeout,
48 TimerChange,
50 BondAdded(ConnHandle, crate::Identity),
52}
53
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56#[derive(Clone, Debug, PartialEq)]
57pub struct BondInformation {
58 pub ltk: LongTermKey,
60 pub identity: Identity,
62 pub is_bonded: bool,
64 pub security_level: SecurityLevel,
66 #[cfg(feature = "legacy-pairing")]
67 pub ediv: u16,
69 #[cfg(feature = "legacy-pairing")]
70 pub rand: [u8; 8],
72 #[cfg(feature = "legacy-pairing")]
73 pub encryption_key_len: u8,
75}
76
77impl BondInformation {
78 pub fn new(identity: Identity, ltk: LongTermKey, security_level: SecurityLevel, is_bonded: bool) -> Self {
80 Self {
81 ltk,
82 identity,
83 is_bonded,
84 security_level,
85 #[cfg(feature = "legacy-pairing")]
86 ediv: 0,
87 #[cfg(feature = "legacy-pairing")]
88 rand: [0; 8],
89 #[cfg(feature = "legacy-pairing")]
90 encryption_key_len: 16,
91 }
92 }
93}
94
95impl core::fmt::Display for BondInformation {
96 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97 write!(f, "Identity {:?} LTK {}", self.identity, self.ltk)
98 }
99}
100
101#[cfg(feature = "defmt")]
102impl defmt::Format for BondInformation {
103 fn format(&self, fmt: defmt::Formatter) {
104 defmt::write!(fmt, "Identity {:?} LTK {}", self.identity, self.ltk);
105 }
106}
107
108struct SecurityManagerData {
110 local_address: Option<Address>,
112 local_irk: Option<IdentityResolvingKey>,
114}
115
116impl SecurityManagerData {
117 fn new() -> Self {
119 Self {
120 local_address: None,
121 local_irk: None,
122 }
123 }
124}
125
126fn add_bond(bond: &mut VecView<BondInformation>, bond_information: BondInformation) -> Result<(), Error> {
128 trace!("[security manager] Add bond for {:?}", bond_information.identity);
129 if let Some(idx) = bond
130 .iter()
131 .position(|b| bond_information.identity.match_identity(&b.identity))
132 {
133 bond[idx] = bond_information;
134 } else {
135 bond.push(bond_information).map_err(|_| Error::OutOfMemory)?;
136 }
137 Ok(())
138}
139
140struct TxPacket<P: PacketPool> {
142 packet: P::Packet,
144 command: Command,
146}
147
148impl<P: PacketPool> TxPacket<P> {
149 const HEADER_SIZE: usize = 5;
151
152 pub fn new(mut packet: P::Packet, command: Command) -> Result<Self, Error> {
154 let packet_data = packet.as_mut();
155 let smp_size = command.payload_size() + 1;
156 packet_data[..2].copy_from_slice(&(smp_size).to_le_bytes());
157 packet_data[2..4].copy_from_slice(&L2CAP_CID_LE_U_SECURITY_MANAGER.to_le_bytes());
158 packet_data[4] = command.into();
159 Ok(Self { packet, command })
160 }
161 pub fn command(&self) -> Command {
163 self.command
164 }
165
166 pub fn payload(&self) -> &[u8] {
168 &self.packet.as_ref()[Self::HEADER_SIZE..Self::HEADER_SIZE + usize::from(self.command.payload_size())]
169 }
170 pub fn payload_mut(&mut self) -> &mut [u8] {
172 &mut self.packet.as_mut()[Self::HEADER_SIZE..Self::HEADER_SIZE + usize::from(self.command.payload_size())]
173 }
174 pub fn total_size(&self) -> usize {
176 usize::from(self.command.payload_size()) + Self::HEADER_SIZE
177 }
178 pub fn into_pdu(self) -> Pdu<P::Packet> {
180 let len = self.total_size();
181 Pdu::new(self.packet, len)
182 }
183}
184
185struct Inner {
187 rng: ChaCha12Rng,
189 secret_key: crypto::SecretKey,
191 public_key: crypto::PublicKey,
193 state: SecurityManagerData,
195 pairing_sm: Option<Pairing>,
197 finished_waker: WakerRegistration,
199 io_capabilities: IoCapabilities,
201 #[cfg(feature = "legacy-pairing")]
203 secure_connections_only: bool,
204}
205
206struct SmpCommand<'a> {
208 command: Command,
209 payload: &'a [u8],
210 peer_address: Address,
211 handle: ConnHandle,
212 peer_identity: Identity,
213}
214
215impl Inner {
216 fn is_idle(&self) -> bool {
217 self.pairing_sm.as_ref().map(|sm| sm.result().is_some()).unwrap_or(true)
218 }
219
220 fn connection_local_address<P>(&self, storage: &ConnectionStorage<P>) -> Result<Address, Error> {
224 if let Some(rpa) = storage.resolvable_addrs.local {
225 return Ok(Address {
226 kind: bt_hci::param::AddrKind::RANDOM,
227 addr: rpa,
228 });
229 }
230 self.state.local_address.ok_or(Error::InvalidValue)
231 }
232
233 fn connection_peer_address<P>(identity_addr: Address, storage: &ConnectionStorage<P>) -> Address {
237 if let Some(rpa) = storage.resolvable_addrs.peer {
238 return Address {
239 kind: bt_hci::param::AddrKind::RANDOM,
240 addr: rpa,
241 };
242 }
243 identity_addr
244 }
245
246 fn handle_peripheral<P: PacketPool>(
247 &mut self,
248 bonds: &mut VecView<BondInformation>,
249 events: &Channel<NoopRawMutex, SecurityEventData, 3>,
250 cmd: &SmpCommand<'_>,
251 connections: &ConnectionManager<'_, P>,
252 storage: &ConnectionStorage<P::Packet>,
253 ) -> Result<(), Error> {
254 let SmpCommand {
255 command,
256 payload,
257 peer_address,
258 handle,
259 peer_identity,
260 } = *cmd;
261 if self.is_idle() {
262 let local_address = self.connection_local_address(storage)?;
263 let peer_address = Self::connection_peer_address(peer_address, storage);
264 let local_io = self.io_capabilities;
265
266 #[cfg(feature = "legacy-pairing")]
267 {
268 let use_legacy = command == Command::PairingRequest
271 && payload.len() >= 4
272 && (!AuthReq::from(payload[2]).secure_connection()
273 || payload[3] < crate::security_manager::constants::ENCRYPTION_KEY_SIZE_128_BITS);
274
275 if use_legacy && self.secure_connections_only {
276 if payload[3] < crate::security_manager::constants::ENCRYPTION_KEY_SIZE_128_BITS {
277 return Err(Error::Security(Reason::EncryptionKeySize));
278 }
279 return Err(Error::Security(Reason::AuthenticationRequirements));
280 }
281
282 if use_legacy {
283 self.pairing_sm = Some(Pairing::new_legacy_peripheral(local_address, peer_address, local_io));
284 } else {
285 self.pairing_sm = Some(Pairing::new_peripheral(local_address, peer_address, local_io));
286 }
287 }
288 #[cfg(not(feature = "legacy-pairing"))]
289 {
290 self.pairing_sm = Some(Pairing::new_peripheral(local_address, peer_address, local_io));
291 }
292 }
293
294 #[cfg(feature = "legacy-pairing")]
297 if command == Command::PairingRequest
298 && payload.len() >= 4
299 && (!AuthReq::from(payload[2]).secure_connection()
300 || payload[3] < crate::security_manager::constants::ENCRYPTION_KEY_SIZE_128_BITS)
301 && self.pairing_sm.as_ref().is_some_and(|p| p.is_lesc_peripheral())
302 {
303 if self.secure_connections_only {
304 if payload[3] < crate::security_manager::constants::ENCRYPTION_KEY_SIZE_128_BITS {
305 return Err(Error::Security(Reason::EncryptionKeySize));
306 }
307 return Err(Error::Security(Reason::AuthenticationRequirements));
308 }
309 let old = self.pairing_sm.take().unwrap();
310 self.pairing_sm = Some(old.switch_to_legacy_peripheral()?);
311 }
312
313 if self.pairing_sm.as_ref().unwrap().is_central() {
314 return Err(Error::InvalidState);
315 }
316 let address = self.pairing_sm.as_ref().unwrap().peer_address();
317
318 if address != Self::connection_peer_address(peer_address, storage) {
328 self.pairing_sm = None;
331 return Err(Error::InvalidValue);
332 }
333
334 let mut ops = PairingOpsImpl {
335 bonds,
336 events,
337 secret_key: &self.secret_key,
338 public_key: &self.public_key,
339 conn_handle: handle,
340 connections,
341 storage,
342 peer_identity,
343 state: &self.state,
344 };
345 self.pairing_sm
346 .as_mut()
347 .unwrap()
348 .handle_l2cap_command(command, payload, &mut ops, &mut self.rng)
349 }
350
351 fn handle_central<P: PacketPool>(
352 &mut self,
353 bonds: &mut VecView<BondInformation>,
354 events: &Channel<NoopRawMutex, SecurityEventData, 3>,
355 cmd: &SmpCommand<'_>,
356 connections: &ConnectionManager<'_, P>,
357 storage: &ConnectionStorage<P::Packet>,
358 ) -> Result<(), Error> {
359 let SmpCommand {
360 command,
361 payload,
362 peer_address,
363 handle,
364 peer_identity,
365 } = *cmd;
366 if self.is_idle() {
367 self.pairing_sm = Some(Pairing::new_central(
368 self.connection_local_address(storage)?,
369 Self::connection_peer_address(peer_address, storage),
370 self.io_capabilities,
371 ));
372 }
373
374 #[cfg(feature = "legacy-pairing")]
377 if command == Command::PairingResponse
378 && payload.len() >= 4
379 && (!AuthReq::from(payload[2]).secure_connection()
380 || payload[3] < crate::security_manager::constants::ENCRYPTION_KEY_SIZE_128_BITS)
381 && self.pairing_sm.as_ref().is_some_and(|p| p.is_lesc_central())
382 {
383 if self.secure_connections_only {
384 if payload[3] < crate::security_manager::constants::ENCRYPTION_KEY_SIZE_128_BITS {
385 return Err(Error::Security(Reason::EncryptionKeySize));
386 }
387 return Err(Error::Security(Reason::AuthenticationRequirements));
388 }
389 let old = self.pairing_sm.take().unwrap();
390 self.pairing_sm = Some(old.switch_to_legacy_central()?);
391 }
392
393 if !self.pairing_sm.as_ref().unwrap().is_central() {
394 return Err(Error::InvalidState);
395 }
396 let address = self.pairing_sm.as_ref().unwrap().peer_address();
397
398 if address != Self::connection_peer_address(peer_address, storage) {
403 self.pairing_sm = None;
406 return Err(Error::InvalidValue);
407 }
408
409 let mut ops = PairingOpsImpl {
410 bonds,
411 events,
412 secret_key: &self.secret_key,
413 public_key: &self.public_key,
414 conn_handle: handle,
415 connections,
416 storage,
417 peer_identity,
418 state: &self.state,
419 };
420 self.pairing_sm
421 .as_mut()
422 .unwrap()
423 .handle_l2cap_command(command, payload, &mut ops, &mut self.rng)
424 }
425
426 fn handle_pairing_event<P: PacketPool>(
427 &mut self,
428 bonds: &mut VecView<BondInformation>,
429 events: &Channel<NoopRawMutex, SecurityEventData, 3>,
430 pairing_event: pairing::Event,
431 connections: &ConnectionManager<'_, P>,
432 storage: &ConnectionStorage<P::Packet>,
433 ) -> Result<(), Error> {
434 if let Some(sm) = self.pairing_sm.as_mut() {
435 let mut ops = PairingOpsImpl {
436 bonds,
437 events,
438 secret_key: &self.secret_key,
439 public_key: &self.public_key,
440 peer_identity: storage.peer_identity.ok_or(Error::InvalidValue)?,
441 conn_handle: storage.handle.ok_or(Error::InvalidValue)?,
442 connections,
443 storage,
444 state: &self.state,
445 };
446 let res = sm.handle_event(pairing_event, &mut ops, &mut self.rng);
447 if res.is_ok() {
448 sm.reset_timeout();
449 let _ = events.try_send(SecurityEventData::TimerChange);
450 }
451 return res;
452 }
453 Ok(())
454 }
455
456 fn handle_encryption_success<P: PacketPool>(
457 &mut self,
458 bonds: &mut VecView<BondInformation>,
459 events: &Channel<NoopRawMutex, SecurityEventData, 3>,
460 encrypted: bool,
461 connections: &ConnectionManager<'_, P>,
462 storage: &mut ConnectionStorage<P::Packet>,
463 ) -> Result<(), Error> {
464 let mut bond = None;
465 let res: Result<(), Error> = if let Some(sm) = self.pairing_sm.as_mut() {
466 let mut ops = PairingOpsImpl {
467 bonds,
468 events,
469 secret_key: &self.secret_key,
470 public_key: &self.public_key,
471 peer_identity: storage.peer_identity.ok_or(Error::InvalidValue)?,
472 connections,
473 storage,
474 conn_handle: storage.handle.ok_or(Error::InvalidValue)?,
475 state: &self.state,
476 };
477 let res = sm.handle_event(pairing::Event::LinkEncryptedResult(encrypted), &mut ops, &mut self.rng);
478 if res.is_ok() {
479 storage.security_level = sm.security_level();
480 storage.bond_rejected = false;
481 #[cfg(feature = "legacy-pairing")]
482 if let Some(bond) = sm.bond_information() {
483 storage.encryption_key_len = bond.encryption_key_len;
484 }
485 }
486 if sm.result().is_some() {
487 self.finished_waker.wake();
488 let _ = events.try_send(SecurityEventData::TimerChange);
489 }
490 res
491 } else if let Some(identity) = storage.peer_identity.as_ref() {
492 match bonds
493 .iter()
494 .find(|bond| bond.identity.match_identity(identity))
495 .cloned()
496 {
497 Some(b) if encrypted => {
498 info!("[smp] Encrypted using bond {:?}", b.identity);
499 storage.security_level = b.security_level;
500 #[cfg(feature = "legacy-pairing")]
501 {
502 storage.encryption_key_len = b.encryption_key_len;
503 }
504 bond = Some(b);
505 }
506 _ => {
507 warn!(
508 "[smp] Either encryption failed to enable or bond not found for {:?}",
509 identity
510 );
511 storage.security_level = SecurityLevel::NoEncryption;
512 }
513 }
514 Ok(())
515 } else {
516 Ok(())
517 };
518
519 if encrypted && storage.security_level != SecurityLevel::NoEncryption {
521 let _ = storage.events.try_send(ConnectionEvent::Encrypted {
522 security_level: storage.security_level,
523 bond,
524 });
525 }
526
527 res
528 }
529
530 fn handle_encryption_failure<P: PacketPool>(
531 &mut self,
532 bonds: &mut VecView<BondInformation>,
533 events: &Channel<NoopRawMutex, SecurityEventData, 3>,
534 connections: &ConnectionManager<'_, P>,
535 storage: &mut ConnectionStorage<P::Packet>,
536 ) {
537 if let Some(sm) = self.pairing_sm.as_mut() {
538 if sm.is_waiting_bonded_encryption() {
542 storage.bond_rejected = true;
543 }
544 let _res = sm.handle_event(
545 pairing::Event::LinkEncryptedResult(false),
546 &mut PairingOpsImpl {
547 bonds,
548 events,
549 secret_key: &self.secret_key,
550 public_key: &self.public_key,
551 peer_identity: storage.peer_identity.unwrap_or_default(),
552 connections,
553 storage,
554 conn_handle: storage.handle.unwrap_or(ConnHandle::new(0)),
555 state: &self.state,
556 },
557 &mut self.rng,
558 );
559 if sm.result().is_some() {
563 self.finished_waker.wake();
564 let _ = events.try_send(SecurityEventData::TimerChange);
565 }
566 }
567 }
568
569 fn initiate<P: PacketPool>(
570 &mut self,
571 bonds: &mut VecView<BondInformation>,
572 events: &Channel<NoopRawMutex, SecurityEventData, 3>,
573 connections: &ConnectionManager<'_, P>,
574 storage: &ConnectionStorage<<P as PacketPool>::Packet>,
575 user_initiated: bool,
576 ) -> Result<(), Error> {
577 let role = storage.role.ok_or(Error::InvalidValue)?;
578
579 if !self.is_idle() {
580 let peer_identity = storage.peer_identity.ok_or(Error::InvalidValue)?;
582 let peer_address = peer_identity.addr;
583 if self
584 .pairing_sm
585 .as_ref()
586 .is_some_and(|sm| sm.peer_address() == peer_address && sm.result().is_none())
587 {
588 return Ok(());
589 }
590 return Err(Error::InvalidState);
591 }
592
593 let handle = storage.handle.ok_or(Error::InvalidValue)?;
594 let peer_identity = storage.peer_identity.ok_or(Error::InvalidValue)?;
595 let local_address = self.connection_local_address(storage)?;
596 let peer_address = Self::connection_peer_address(peer_identity.addr, storage);
597 let local_io = self.io_capabilities;
598 let mut ops = PairingOpsImpl {
599 bonds,
600 events,
601 secret_key: &self.secret_key,
602 public_key: &self.public_key,
603 conn_handle: handle,
604 connections,
605 storage,
606 peer_identity,
607 state: &self.state,
608 };
609 if role == LeConnRole::Peripheral {
610 self.pairing_sm = Some(Pairing::initiate_peripheral(
611 local_address,
612 peer_address,
613 &mut ops,
614 local_io,
615 user_initiated,
616 )?);
617 } else {
618 self.pairing_sm = Some(Pairing::initiate_central(
619 local_address,
620 peer_address,
621 &mut ops,
622 local_io,
623 user_initiated,
624 )?);
625 }
626 Ok(())
627 }
628}
629
630pub struct SecurityManager<'d> {
632 inner: RefCell<Inner>,
634 bonds: &'d RefCell<VecView<BondInformation>>,
636 events: Channel<NoopRawMutex, SecurityEventData, 3>,
638}
639
640impl<'d> SecurityManager<'d> {
641 pub(crate) fn new(bonds: &'d RefCell<VecView<BondInformation>>) -> Self {
643 let mut rng = ChaCha12Rng::from_seed([0u8; 32]);
644 let secret_key = crypto::SecretKey::new(&mut rng);
645 let public_key = secret_key.public_key();
646 Self {
647 inner: RefCell::new(Inner {
648 rng,
649 secret_key,
650 public_key,
651 state: SecurityManagerData::new(),
652 pairing_sm: None,
653 finished_waker: WakerRegistration::new(),
654 io_capabilities: IoCapabilities::NoInputNoOutput,
655 #[cfg(feature = "legacy-pairing")]
656 secure_connections_only: false,
657 }),
658 bonds,
659 events: Channel::new(),
660 }
661 }
662
663 pub(crate) fn set_io_capabilities(&self, io_capabilities: IoCapabilities) {
665 self.inner.borrow_mut().io_capabilities = io_capabilities;
666 }
667
668 #[cfg(feature = "legacy-pairing")]
671 pub(crate) fn set_secure_connections_only(&self, enabled: bool) {
672 self.inner.borrow_mut().secure_connections_only = enabled;
673 }
674
675 pub(crate) fn set_random_generator_seed(&self, random_seed: [u8; 32]) {
677 let mut inner = self.inner.borrow_mut();
678 inner.rng = ChaCha12Rng::from_seed(random_seed);
679 inner.secret_key = crypto::SecretKey::new(&mut inner.rng);
680 inner.public_key = inner.secret_key.public_key();
681 }
682
683 pub(crate) fn set_local_address(&self, address: Address) {
685 self.inner.borrow_mut().state.local_address = Some(address);
686 }
687
688 fn is_idle(&self) -> bool {
690 self.inner.borrow().is_idle()
691 }
692
693 pub(crate) fn is_pairing_in_progress(&self, address: Address) -> bool {
694 let inner = self.inner.borrow();
695 match &inner.pairing_sm {
696 Some(sm) => sm.peer_address() == address && sm.result().is_none(),
697 None => false,
698 }
699 }
700
701 pub(crate) fn peer_address(&self) -> Option<Address> {
703 self.inner
704 .borrow()
705 .pairing_sm
706 .as_ref()
707 .and_then(|sm| sm.result().is_none().then_some(sm.peer_address()))
708 }
709
710 pub(crate) async fn wait_finished(&self, address: Address) -> Result<(), Error> {
711 poll_fn(|cx| {
712 let mut inner = self.inner.borrow_mut();
713 inner.finished_waker.register(cx.waker());
714 match &inner.pairing_sm {
715 Some(sm) => {
716 if sm.peer_address() != address {
717 return Poll::Ready(Err(Error::Busy));
718 }
719 match sm.result() {
720 Some(result) => Poll::Ready(result),
721 None => Poll::Pending,
722 }
723 }
724 None => Poll::Ready(Err(Error::Disconnected)),
725 }
726 })
727 .await
728 }
729
730 pub(crate) fn get_peer_bond_information(&self, identity: &Identity) -> Option<BondInformation> {
731 trace!("[security manager] Find long term key for {:?}", identity);
732 self.bonds.borrow().iter().find_map(|bond| {
733 if bond.identity.match_identity(identity) {
734 Some(bond.clone())
735 } else {
736 None
737 }
738 })
739 }
740
741 pub(crate) fn get_local_oob_data(&self) -> pairing::OobData {
747 let mut inner = self.inner.borrow_mut();
748 let r = crypto::Nonce::new(&mut inner.rng);
749 let c = r.f4(inner.public_key.x(), inner.public_key.x(), 0);
750 pairing::OobData {
751 random: r.0.to_le_bytes(),
752 confirm: c.0.to_le_bytes(),
753 }
754 }
755
756 pub(crate) fn get_local_address(&self) -> Option<Address> {
758 self.inner.borrow().state.local_address
759 }
760
761 pub(crate) fn set_local_irk(&self, irk: IdentityResolvingKey) {
763 self.inner.borrow_mut().state.local_irk = Some(irk);
764 }
765
766 pub(crate) fn get_local_irk(&self) -> Option<IdentityResolvingKey> {
769 self.inner.borrow().state.local_irk
770 }
771
772 pub(crate) fn add_bond_information(&self, bond_information: BondInformation) -> Result<(), Error> {
774 add_bond(&mut self.bonds.borrow_mut(), bond_information)
775 }
776
777 pub(crate) fn remove_bond_information(&self, identity: Identity) -> Result<(), Error> {
779 trace!("[security manager] Remove bond for {:?}", identity);
780 let mut bonds = self.bonds.borrow_mut();
781 let index = bonds.iter().position(|bond| bond.identity.match_identity(&identity));
782 match index {
783 Some(index) => {
784 bonds.remove(index);
785 Ok(())
786 }
787 None => Err(Error::NotFound),
788 }
789 }
790
791 pub(crate) fn get_bond_information(&self) -> Ref<'_, VecView<BondInformation>> {
793 self.bonds.borrow()
794 }
795
796 pub(crate) fn bond_count(&self) -> usize {
798 self.bonds.borrow().len()
799 }
800
801 pub(crate) fn get_bond(&self, index: usize) -> Option<BondInformation> {
803 self.bonds.borrow().get(index).cloned()
804 }
805
806 pub(crate) fn get_bond_identity(&self, index: usize) -> Option<Identity> {
808 self.bonds.borrow().get(index).map(|b| b.identity)
809 }
810
811 fn parse_smp_command<P: PacketPool>(pdu: Pdu<P::Packet>) -> Result<(Command, [u8; 72], usize), Error> {
812 let mut buffer = [0u8; 72];
813 let size = {
814 let size = pdu.len().min(buffer.len());
815 buffer[..size].copy_from_slice(&pdu.as_ref()[..size]);
816 size
817 };
818 if size < 2 {
819 error!("[security manager] Payload size too small {}", size);
820 return Err(Error::Security(Reason::InvalidParameters));
821 }
822 let payload_len = size - 1;
823 let command = match Command::try_from(buffer[0]) {
824 Ok(command) => {
825 if usize::from(command.payload_size()) != payload_len {
826 error!("[security manager] Payload size mismatch for command {}", command);
827 return Err(Error::Security(Reason::InvalidParameters));
828 }
829 command
830 }
831 Err(_) => return Err(Error::Security(Reason::CommandNotSupported)),
832 };
833 Ok((command, buffer, size))
834 }
835
836 fn handle_peripheral<P: PacketPool>(
837 &self,
838 pdu: Pdu<P::Packet>,
839 connections: &ConnectionManager<'_, P>,
840 storage: &ConnectionStorage<P::Packet>,
841 ) -> Result<(), Error> {
842 let (command, buffer, size) = Self::parse_smp_command::<P>(pdu)?;
843 let cmd = SmpCommand {
844 command,
845 payload: &buffer[1..size],
846 peer_address: storage.peer_identity.ok_or(Error::InvalidValue)?.addr,
847 handle: storage.handle.ok_or(Error::InvalidValue)?,
848 peer_identity: storage.peer_identity.ok_or(Error::InvalidValue)?,
849 };
850 self.inner.borrow_mut().handle_peripheral(
851 &mut self.bonds.borrow_mut(),
852 &self.events,
853 &cmd,
854 connections,
855 storage,
856 )
857 }
858
859 fn handle_central<P: PacketPool>(
860 &self,
861 pdu: Pdu<P::Packet>,
862 connections: &ConnectionManager<'_, P>,
863 storage: &ConnectionStorage<P::Packet>,
864 ) -> Result<(), Error> {
865 let (command, buffer, size) = Self::parse_smp_command::<P>(pdu)?;
866 let cmd = SmpCommand {
867 command,
868 payload: &buffer[1..size],
869 peer_address: storage.peer_identity.ok_or(Error::InvalidValue)?.addr,
870 handle: storage.handle.ok_or(Error::InvalidValue)?,
871 peer_identity: storage.peer_identity.ok_or(Error::InvalidValue)?,
872 };
873 self.inner
874 .borrow_mut()
875 .handle_central(&mut self.bonds.borrow_mut(), &self.events, &cmd, connections, storage)
876 }
877
878 pub(crate) fn handle_l2cap_command<P: PacketPool>(
880 &self,
881 pdu: Pdu<P::Packet>,
882 connections: &ConnectionManager<P>,
883 storage: &ConnectionStorage<P::Packet>,
884 ) -> Result<(), Error> {
885 let role = storage.role.ok_or(Error::InvalidValue)?;
886
887 let result = if role == LeConnRole::Peripheral {
888 self.handle_peripheral(pdu, connections, storage)
889 } else {
890 self.handle_central(pdu, connections, storage)
891 };
892
893 {
894 let mut inner = self.inner.borrow_mut();
895 if inner.is_idle() {
896 inner.finished_waker.wake();
897 }
898 if result.is_ok() {
899 if let Some(sm) = inner.pairing_sm.as_mut() {
900 sm.reset_timeout();
901 let _ = self.events.try_send(SecurityEventData::TimerChange);
902 }
903 }
904 }
905
906 if result.is_err() {
907 if let Err(e) = self.handle_security_error(connections, storage, &result) {
908 error!("[security manager] Failed sending pairing failed message! {:?}", e);
909 }
910 }
911 result
912 }
913
914 fn handle_security_error<P: PacketPool>(
915 &self,
916 connections: &ConnectionManager<P>,
917 storage: &ConnectionStorage<<P as PacketPool>::Packet>,
918 result: &Result<(), Error>,
919 ) -> Result<(), Error> {
920 if let Err(error) = result {
921 let reason = if let Error::Security(secuity_error) = error {
922 *secuity_error
923 } else {
924 Reason::UnspecifiedReason
925 };
926
927 error!("Handling of command failed {:?}", error);
928
929 if *error != Error::Timeout {
931 let handle = storage.handle.ok_or(Error::InvalidValue)?;
932 let mut packet = self.prepare_packet(Command::PairingFailed, connections)?;
933 let payload = packet.payload_mut();
934 payload[0] = u8::from(reason);
935
936 match self.try_send_packet(packet, connections, handle) {
937 Ok(()) => (),
938 Err(error) => {
939 error!("[security manager] Failed to send pairing failed {:?}", error);
940 return Err(error);
941 }
942 }
943 }
944 }
945
946 Ok(())
947 }
948
949 pub fn initiate<P: PacketPool>(
951 &self,
952 connections: &ConnectionManager<'_, P>,
953 storage: &ConnectionStorage<<P as PacketPool>::Packet>,
954 user_initiated: bool,
955 ) -> Result<(), Error> {
956 if storage.security_level != SecurityLevel::NoEncryption {
957 return Err(Error::Security(Reason::UnspecifiedReason));
958 }
959 self.inner.borrow_mut().initiate(
960 &mut self.bonds.borrow_mut(),
961 &self.events,
962 connections,
963 storage,
964 user_initiated,
965 )
966 }
967
968 pub(crate) fn cancel_timeout(&self) {
970 let mut inner = self.inner.borrow_mut();
971 if let Some(pairing) = inner.pairing_sm.as_mut() {
972 pairing.mark_timeout();
973 inner.finished_waker.wake();
974 }
975 }
976
977 pub(crate) fn disconnect(&self, identity: &Identity) {
979 {
980 let mut inner = self.inner.borrow_mut();
981 if inner
982 .pairing_sm
983 .as_ref()
984 .is_some_and(|sm| sm.peer_address() == identity.addr)
985 {
986 inner.pairing_sm = None;
987 inner.finished_waker.wake();
988 }
989 }
990 self.bonds
991 .borrow_mut()
992 .retain(|x| x.is_bonded || x.identity != *identity);
993 }
994
995 pub(crate) fn handle_hci_le_event<P: PacketPool>(
997 &self,
998 event: LeEventPacket,
999 connections: &ConnectionManager<'_, P>,
1000 ) -> Result<(), Error> {
1001 #[allow(clippy::single_match)]
1002 match event.kind {
1003 LeEventKind::LeLongTermKeyRequest => {
1004 let event_data = LeLongTermKeyRequest::from_hci_bytes_complete(event.data)?;
1005 self.try_send_event(SecurityEventData::SendLongTermKey(
1006 event_data.handle,
1007 event_data.encrypted_diversifier,
1008 event_data.random_number,
1009 ))?;
1010 }
1011 _ => (),
1012 }
1013 Ok(())
1014 }
1015
1016 pub(crate) fn handle_hci_event<P: PacketPool>(
1018 &self,
1019 event: EventPacket,
1020 connections: &ConnectionManager<'_, P>,
1021 ) -> Result<(), Error> {
1022 let encryption_event = match event.kind {
1024 EventKind::EncryptionChangeV1 => {
1025 let e = EncryptionChangeV1::from_hci_bytes_complete(event.data)?;
1026 Some((e.handle, e.status, e.enabled != EncryptionEnabledLevel::Off))
1027 }
1028 EventKind::EncryptionKeyRefreshComplete => {
1029 let e = EncryptionKeyRefreshComplete::from_hci_bytes_complete(event.data)?;
1030 Some((e.handle, e.status, true))
1032 }
1033 _ => None,
1034 };
1035
1036 if let Some((handle, status, encrypted)) = encryption_event {
1037 match status.to_result() {
1038 Ok(()) => {
1039 trace!("[smp] Encryption event (encrypted={})", encrypted);
1040 connections.with_connected_handle(handle, |storage| {
1041 let res = self.inner.borrow_mut().handle_encryption_success(
1042 &mut self.bonds.borrow_mut(),
1043 &self.events,
1044 encrypted,
1045 connections,
1046 storage,
1047 );
1048 let _ = self.handle_security_error(connections, storage, &res);
1049 res
1050 })?;
1051 }
1052 Err(error) => {
1053 error!("[security manager] Encryption event error {:?}", error);
1054 connections.with_connected_handle(handle, |storage| {
1055 self.inner.borrow_mut().handle_encryption_failure(
1056 &mut self.bonds.borrow_mut(),
1057 &self.events,
1058 connections,
1059 storage,
1060 );
1061 Ok(())
1062 })?;
1063 }
1064 }
1065 }
1066 Ok(())
1067 }
1068
1069 fn handle_event<P: PacketPool>(
1070 &self,
1071 pairing_event: pairing::Event,
1072 connections: &ConnectionManager<'_, P>,
1073 storage: &ConnectionStorage<P::Packet>,
1074 ) -> Result<(), Error> {
1075 let res = self.inner.borrow_mut().handle_pairing_event(
1076 &mut self.bonds.borrow_mut(),
1077 &self.events,
1078 pairing_event,
1079 connections,
1080 storage,
1081 );
1082 if res.is_err() {
1083 if let Err(e) = self.handle_security_error(connections, storage, &res) {
1084 error!("[security manager] Failed sending pairing failed message! {:?}", e);
1085 }
1086 }
1087 res
1088 }
1089
1090 pub(crate) fn handle_pass_key_input<P: PacketPool>(
1091 &self,
1092 input: u32,
1093 connections: &ConnectionManager<'_, P>,
1094 storage: &ConnectionStorage<P::Packet>,
1095 ) -> Result<(), Error> {
1096 self.handle_event(pairing::Event::PassKeyInput(input), connections, storage)
1097 }
1098
1099 pub(crate) fn handle_oob_data_received<P: PacketPool>(
1100 &self,
1101 local_oob: pairing::OobData,
1102 peer_oob: pairing::OobData,
1103 connections: &ConnectionManager<'_, P>,
1104 storage: &ConnectionStorage<P::Packet>,
1105 ) -> Result<(), Error> {
1106 self.handle_event(
1107 pairing::Event::OobDataReceived {
1108 local: local_oob,
1109 peer: peer_oob,
1110 },
1111 connections,
1112 storage,
1113 )
1114 }
1115
1116 pub(crate) fn handle_pass_key_confirm<P: PacketPool>(
1117 &self,
1118 confirmed: bool,
1119 connections: &ConnectionManager<'_, P>,
1120 storage: &ConnectionStorage<<P as PacketPool>::Packet>,
1121 ) -> Result<(), Error> {
1122 let pairing_event = match confirmed {
1123 true => pairing::Event::PassKeyConfirm,
1124 false => pairing::Event::PassKeyCancel,
1125 };
1126 self.handle_event(pairing_event, connections, storage)
1127 }
1128
1129 fn prepare_packet<P: PacketPool>(
1131 &self,
1132 command: Command,
1133 connections: &ConnectionManager<P>,
1134 ) -> Result<TxPacket<P>, Error> {
1135 let packet = P::allocate().ok_or(Error::OutOfMemory)?;
1136 TxPacket::new(packet, command)
1137 }
1138
1139 fn try_send_packet<P: PacketPool>(
1141 &self,
1142 packet: TxPacket<P>,
1143 connections: &ConnectionManager<P>,
1144 handle: ConnHandle,
1145 ) -> Result<(), Error> {
1146 let len = packet.total_size();
1147 trace!("[security manager] Send {} {}", packet.command, len);
1148 connections.try_outbound(handle, packet.into_pdu())
1149 }
1150
1151 fn try_send_event(&self, event: SecurityEventData) -> Result<(), Error> {
1153 self.events.try_send(event).map_err(|_| Error::OutOfMemory)
1154 }
1155
1156 pub(crate) fn poll_events(&self) -> impl Future<Output = Result<SecurityEventData, TimeoutError>> + use<'_, 'd> {
1158 let deadline = self
1159 .inner
1160 .borrow()
1161 .pairing_sm
1162 .as_ref()
1163 .map(|x| x.timeout_at())
1164 .unwrap_or(Instant::now() + constants::TIMEOUT_DISABLE);
1165 poll_fn(|cx| self.events.poll_receive(cx)).with_deadline(deadline)
1167 }
1168}
1169
1170struct PairingOpsImpl<'sm, 'cm, 'cm2, 'cs, P: PacketPool> {
1171 bonds: &'sm mut VecView<BondInformation>,
1172 events: &'sm Channel<NoopRawMutex, SecurityEventData, 3>,
1173 secret_key: &'sm crypto::SecretKey,
1174 public_key: &'sm crypto::PublicKey,
1175 connections: &'cm ConnectionManager<'cm2, P>,
1176 storage: &'cs ConnectionStorage<P::Packet>,
1177 conn_handle: ConnHandle,
1178 peer_identity: Identity,
1179 state: &'sm SecurityManagerData,
1180}
1181
1182impl<'sm, 'cm, 'cm2, 'cs, P: PacketPool> PairingOps<P> for PairingOpsImpl<'sm, 'cm, 'cm2, 'cs, P> {
1183 fn try_send_packet(&mut self, packet: TxPacket<P>) -> Result<(), Error> {
1184 let len = packet.total_size();
1185 trace!("[security manager] Send {} {}", packet.command, len);
1186 self.connections.try_outbound(self.conn_handle, packet.into_pdu())?;
1187 let _ = self.events.try_send(SecurityEventData::TimerChange);
1188 Ok(())
1189 }
1190
1191 fn try_update_bond_information(&mut self, bond: &BondInformation) -> Result<(), Error> {
1192 add_bond(self.bonds, bond.clone())?;
1193 if bond.identity.irk.is_some() {
1194 let _ = self
1195 .events
1196 .try_send(SecurityEventData::BondAdded(self.conn_handle, bond.identity));
1197 }
1198 Ok(())
1199 }
1200
1201 fn find_bond(&self) -> Option<BondInformation> {
1202 self.bonds
1203 .iter()
1204 .find(|x| x.identity.match_identity(&self.peer_identity))
1205 .cloned()
1206 }
1207
1208 fn try_enable_encryption(
1209 &mut self,
1210 ltk: &LongTermKey,
1211 security_level: SecurityLevel,
1212 is_bonded: bool,
1213 #[cfg(feature = "legacy-pairing")] ediv: u16,
1214 #[cfg(feature = "legacy-pairing")] rand: [u8; 8],
1215 #[cfg(feature = "legacy-pairing")] encryption_key_len: u8,
1216 ) -> Result<BondInformation, Error> {
1217 info!("Enabling encryption for {:?}", self.peer_identity);
1218 let bond_info = BondInformation {
1219 ltk: *ltk,
1220 identity: self.peer_identity,
1221 is_bonded,
1222 security_level,
1223 #[cfg(feature = "legacy-pairing")]
1224 ediv,
1225 #[cfg(feature = "legacy-pairing")]
1226 rand,
1227 #[cfg(feature = "legacy-pairing")]
1228 encryption_key_len,
1229 };
1230 self.try_update_bond_information(&bond_info)?;
1231 self.events
1232 .try_send(SecurityEventData::EnableEncryption(self.conn_handle, bond_info.clone()))
1233 .map_err(|_| Error::OutOfMemory)?;
1234 Ok(bond_info)
1235 }
1236
1237 fn try_enable_bonded_encryption(&mut self) -> Result<Option<BondInformation>, Error> {
1238 if self.storage.bond_rejected {
1239 return Ok(None);
1240 }
1241 if let Some(bond) = self.find_bond() {
1242 self.events
1243 .try_send(SecurityEventData::EnableEncryption(self.conn_handle, bond.clone()))
1244 .map_err(|_| Error::OutOfMemory)?;
1245 Ok(Some(bond))
1246 } else {
1247 Ok(None)
1248 }
1249 }
1250
1251 fn bonding_flag(&self) -> BondingFlag {
1252 if self.storage.bondable {
1253 BondingFlag::Bonding
1254 } else {
1255 BondingFlag::NoBonding
1256 }
1257 }
1258
1259 fn connection_handle(&mut self) -> ConnHandle {
1260 self.conn_handle
1261 }
1262
1263 fn try_send_connection_event(&mut self, event: ConnectionEvent) -> Result<(), Error> {
1264 let timer_changed = matches!(
1265 event,
1266 ConnectionEvent::PairingComplete { .. } | ConnectionEvent::PairingFailed(_)
1267 );
1268 self.storage.events.try_send(event).map_err(|_| Error::OutOfMemory)?;
1269 if timer_changed {
1270 let _ = self.events.try_send(SecurityEventData::TimerChange);
1271 }
1272 Ok(())
1273 }
1274
1275 fn oob_available(&self) -> bool {
1276 self.storage.oob_available
1277 }
1278
1279 fn secret_key(&self) -> &crypto::SecretKey {
1280 self.secret_key
1281 }
1282
1283 fn public_key(&self) -> &crypto::PublicKey {
1284 self.public_key
1285 }
1286
1287 fn local_irk(&self) -> [u8; 16] {
1288 self.state.local_irk.map(|k| k.to_le_bytes()).unwrap_or_default()
1289 }
1290
1291 fn local_identity_address(&self) -> Result<Address, Error> {
1292 self.state.local_address.ok_or(Error::InvalidValue)
1293 }
1294}