Skip to main content

trouble_host/security_manager/
mod.rs

1#![warn(missing_docs)]
2//! # Bluetooth Security Manager
3// ([Vol 3] Part H, Section 3.5.5)
4
5mod 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
40/// Events of interest to the security manager
41pub(crate) enum SecurityEventData {
42    /// A long term key request has been issued (handle, ediv, rand)
43    SendLongTermKey(ConnHandle, u16, [u8; 8]),
44    /// Enable encryption on channel
45    EnableEncryption(ConnHandle, BondInformation),
46    /// Pairing timeout
47    Timeout,
48    /// Pairing timer changed
49    TimerChange,
50    /// A new bond was stored during pairing
51    BondAdded(ConnHandle, crate::Identity),
52}
53
54/// Bond Information
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56#[derive(Clone, Debug, PartialEq)]
57pub struct BondInformation {
58    /// Long Term Key (LTK)
59    pub ltk: LongTermKey,
60    /// Peer identity
61    pub identity: Identity,
62    /// True if this bond information is from a bonded pairing
63    pub is_bonded: bool,
64    /// Security level of this long term key.
65    pub security_level: SecurityLevel,
66    #[cfg(feature = "legacy-pairing")]
67    /// Encrypted Diversifier (0 for LESC, non-zero for legacy)
68    pub ediv: u16,
69    #[cfg(feature = "legacy-pairing")]
70    /// Random Number (all zeros for LESC, non-zero for legacy)
71    pub rand: [u8; 8],
72    #[cfg(feature = "legacy-pairing")]
73    /// Negotiated encryption key length in bytes (16 for LESC)
74    pub encryption_key_len: u8,
75}
76
77impl BondInformation {
78    /// Create a BondInformation
79    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
108/// Security manager data
109struct SecurityManagerData {
110    /// Local device address
111    local_address: Option<Address>,
112    /// Local Identity Resolving Key (set when privacy is enabled)
113    local_irk: Option<IdentityResolvingKey>,
114}
115
116impl SecurityManagerData {
117    /// Create a new security manager data structure
118    fn new() -> Self {
119        Self {
120            local_address: None,
121            local_irk: None,
122        }
123    }
124}
125
126/// Add or replace a bond in the given bond storage.
127fn 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
140/// Packet structure for sending security manager protocol (SMP) commands
141struct TxPacket<P: PacketPool> {
142    /// Underlying packet
143    packet: P::Packet,
144    /// Command to send
145    command: Command,
146}
147
148impl<P: PacketPool> TxPacket<P> {
149    /// Size of L2CAP header and command
150    const HEADER_SIZE: usize = 5;
151
152    /// Get a packet from the pool
153    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    /// Packet command
162    pub fn command(&self) -> Command {
163        self.command
164    }
165
166    /// Packet payload
167    pub fn payload(&self) -> &[u8] {
168        &self.packet.as_ref()[Self::HEADER_SIZE..Self::HEADER_SIZE + usize::from(self.command.payload_size())]
169    }
170    /// Package mutable payload
171    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    /// Package size
175    pub fn total_size(&self) -> usize {
176        usize::from(self.command.payload_size()) + Self::HEADER_SIZE
177    }
178    /// Create a PDU from the packet
179    pub fn into_pdu(self) -> Pdu<P::Packet> {
180        let len = self.total_size();
181        Pdu::new(self.packet, len)
182    }
183}
184
185/// Inner mutable state of the security manager
186struct Inner {
187    /// Random generator
188    rng: ChaCha12Rng,
189    /// Persistent LESC keypair (generated once when RNG is seeded)
190    secret_key: crypto::SecretKey,
191    /// Corresponding public key
192    public_key: crypto::PublicKey,
193    /// Security manager data
194    state: SecurityManagerData,
195    /// State of an ongoing pairing
196    pairing_sm: Option<Pairing>,
197    /// Waker for pairing finished
198    finished_waker: WakerRegistration,
199    /// Io capabilities
200    io_capabilities: IoCapabilities,
201    /// When true, reject legacy pairing even if the feature is compiled in
202    #[cfg(feature = "legacy-pairing")]
203    secure_connections_only: bool,
204}
205
206/// Parsed SMP command data extracted from an L2CAP PDU
207struct 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    /// Get the local address to use for pairing calculations.
221    /// When privacy is enabled and a local RPA was used for this connection, use it;
222    /// otherwise fall back to the identity address.
223    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    /// Get the peer address to use for pairing calculations.
234    /// When privacy is enabled and a peer RPA was used for this connection, use it;
235    /// otherwise fall back to the identity address.
236    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                // Check if peer supports SC by peeking at PairingRequest AuthReq byte,
269                // or if peer requests a key size smaller than LESC requires
270                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        // Check if we need to switch from LESC to legacy peripheral
295        // when receiving a PairingRequest without SC flag or with insufficient key size
296        #[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        // The state machine stores the connection-level peer address: the RPA,
319        // when the controller resolved one (see `connection_peer_address`, and
320        // the SMP confirm-value calculations that require the on-air address).
321        // The incoming command carries the *resolved identity* address, so the
322        // command address must be normalized the same way before comparing.
323        // Comparing them directly rejected every pairing attempt from a peer
324        // whose RPA was resolved against a stored bond -- i.e. a bonded peer
325        // that lost its keys could never re-pair until the local bond (and so
326        // the resolving-list entry) was deleted.
327        if address != Self::connection_peer_address(peer_address, storage) {
328            // A pairing is already in progress with a *different* peer address;
329            // reject and reset rather than mixing two exchanges.
330            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        // Check if we need to switch from LESC to legacy central
375        // when receiving a PairingResponse without SC flag or with insufficient key size
376        #[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        // See the matching check in `handle_peripheral`: the state machine
399        // stores the connection-level peer address (the RPA when one was
400        // resolved), while the command carries the resolved identity, so the
401        // command address must be normalized before comparing.
402        if address != Self::connection_peer_address(peer_address, storage) {
403            // A pairing is already in progress with a *different* peer address;
404            // reject and reset rather than mixing two exchanges.
405            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        // Emit an Encrypted event for both new-pairing and resumed-bond paths.
520        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 we were waiting for bonded encryption, mark the bond as
539            // rejected on this connection so the next pairing attempt will
540            // skip bonded encryption and initiate fresh pairing instead.
541            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            // Don't call handle_security_error here: sending SMP PairingFailed
560            // for an HCI-level encryption failure would cause the peer to
561            // delete its bond information, preventing future re-encryption.
562            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            // If pairing is already in progress for this peer, consider the request fulfilled.
581            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
630/// Security manager that handles SM packet
631pub struct SecurityManager<'d> {
632    /// Inner mutable state
633    inner: RefCell<Inner>,
634    /// Bond storage (externally owned by HostResources)
635    bonds: &'d RefCell<VecView<BondInformation>>,
636    /// Received events
637    events: Channel<NoopRawMutex, SecurityEventData, 3>,
638}
639
640impl<'d> SecurityManager<'d> {
641    /// Create a new SecurityManager
642    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    /// Set the IO capabilities
664    pub(crate) fn set_io_capabilities(&self, io_capabilities: IoCapabilities) {
665        self.inner.borrow_mut().io_capabilities = io_capabilities;
666    }
667
668    /// Enable or disable secure connections only mode.
669    /// When enabled, legacy pairing is rejected even if the feature is compiled in.
670    #[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    /// Seed the security manager's CSPRNG and regenerate the persistent LESC keypair.
676    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    /// Set the current local address
684    pub(crate) fn set_local_address(&self, address: Address) {
685        self.inner.borrow_mut().state.local_address = Some(address);
686    }
687
688    /// Returns true if no pairing is currently in progress.
689    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    /// The address of the peer that is currently being paired with.
702    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    /// Generate local OOB data for LESC pairing.
742    ///
743    /// The returned data should be exchanged with the peer via an out-of-band channel.
744    /// The persistent keypair is used so the confirm value matches the public key
745    /// that will be sent during pairing.
746    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    /// Get the current local address.
757    pub(crate) fn get_local_address(&self) -> Option<Address> {
758        self.inner.borrow().state.local_address
759    }
760
761    /// Set the local Identity Resolving Key (IRK) for privacy.
762    pub(crate) fn set_local_irk(&self, irk: IdentityResolvingKey) {
763        self.inner.borrow_mut().state.local_irk = Some(irk);
764    }
765
766    /// Get the local Identity Resolving Key (IRK).
767    /// Returns `Some` when privacy is enabled, `None` otherwise.
768    pub(crate) fn get_local_irk(&self) -> Option<IdentityResolvingKey> {
769        self.inner.borrow().state.local_irk
770    }
771
772    /// Add a bonded device
773    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    /// Remove a bonded device
778    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    /// Get bonded devices
792    pub(crate) fn get_bond_information(&self) -> Ref<'_, VecView<BondInformation>> {
793        self.bonds.borrow()
794    }
795
796    /// Get the number of bonded devices
797    pub(crate) fn bond_count(&self) -> usize {
798        self.bonds.borrow().len()
799    }
800
801    /// Get a bond by its index
802    pub(crate) fn get_bond(&self, index: usize) -> Option<BondInformation> {
803        self.bonds.borrow().get(index).cloned()
804    }
805
806    /// Get the identity of a bonded device by index
807    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    /// Handle packet
879    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            // Cease sending security manager messages on timeout
930            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    /// Initiate pairing
950    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    /// Cancel pairing after timeout
969    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    /// Channel disconnected
978    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    /// Handle recevied events from HCI
996    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    /// Handle recevied events from HCI
1017    pub(crate) fn handle_hci_event<P: PacketPool>(
1018        &self,
1019        event: EventPacket,
1020        connections: &ConnectionManager<'_, P>,
1021    ) -> Result<(), Error> {
1022        // Extract (handle, status, encrypted) from either encryption event type
1023        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                // Key refresh implies encryption is still on
1031                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    /// Prepare a packet for sending
1130    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    /// Send a packet
1140    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    /// Send a packet
1152    fn try_send_event(&self, event: SecurityEventData) -> Result<(), Error> {
1153        self.events.try_send(event).map_err(|_| Error::OutOfMemory)
1154    }
1155
1156    /// Poll for security manager work
1157    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        // try to pop an event from the channel
1166        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}