diff --git a/.github/workflows/run-test.yml b/.github/workflows/run-test.yml index 81b2a92..917d195 100644 --- a/.github/workflows/run-test.yml +++ b/.github/workflows/run-test.yml @@ -17,6 +17,12 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy + args: --all-features + - name: Clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --no-default-features format: runs-on: ubuntu-latest steps: @@ -49,6 +55,10 @@ jobs: run: | set -ex cargo build + - name: Build no security + run: | + set -ex + cargo build --no-default-features test: runs-on: ubuntu-latest steps: @@ -63,4 +73,8 @@ jobs: - name: Test run: | set -ex - cargo test \ No newline at end of file + cargo test + - name: Test no security + run: | + set -ex + cargo test --no-default-features \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 6b159d3..1b7f638 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,20 +17,17 @@ categories = ["embedded", "network-programming", "no-std"] keywords = ["WPAN"] [features] +default = ["security"] +security = ["cipher", "ccm"] [dependencies] hash32 = "0.2.1" hash32-derive = "0.1" byte = "0.2.7" defmt = { version = ">=0.2.0,<0.4", optional = true } +cipher = {version = "0.3.0", default-features = false, optional = true} +ccm = { version = "0.4.0", default-features = false, optional = true} -[dependencies.ccm] -version = "0.4.0" -default-features = false - -[dependencies.cipher] -version = "0.3.0" -default-features = false [dependencies.serde] version = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 2061832..84284d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,4 +25,5 @@ #[macro_use] mod utils; +#[allow(unused_imports)] pub mod mac; diff --git a/src/mac/beacon.rs b/src/mac/beacon.rs index fadf991..025cae0 100644 --- a/src/mac/beacon.rs +++ b/src/mac/beacon.rs @@ -102,7 +102,7 @@ const ASSOCIATION_PERMIT: u8 = 0b1000_0000; impl TryRead<'_> for SuperframeSpecification { fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> { let offset = &mut 0; - check_len(&bytes, 2)?; + check_len(bytes, 2)?; let byte: u8 = bytes.read(offset)?; let beacon_order = BeaconOrder::from(byte & 0x0f); let superframe_order = SuperframeOrder::from((byte >> 4) & 0x0f); @@ -130,8 +130,8 @@ impl TryRead<'_> for SuperframeSpecification { impl TryWrite for SuperframeSpecification { fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result { let offset = &mut 0; - let bo = u8::from(self.beacon_order.clone()); - let so = u8::from(self.superframe_order.clone()); + let bo = u8::from(self.beacon_order); + let so = u8::from(self.superframe_order); bytes.write(offset, (bo & 0x0f) | (so << 4))?; let ble = if self.battery_life_extension { BATTERY_LIFE_EXTENSION @@ -189,10 +189,16 @@ impl GuaranteedTimeSlotDescriptor { } } +impl Default for GuaranteedTimeSlotDescriptor { + fn default() -> Self { + Self::new() + } +} + impl TryRead<'_> for GuaranteedTimeSlotDescriptor { fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> { let offset = &mut 0; - check_len(&bytes, 3)?; + check_len(bytes, 3)?; let short_address = bytes.read(offset)?; let byte: u8 = bytes.read(offset)?; let starting_slot = byte & 0x0f; @@ -259,6 +265,12 @@ impl GuaranteedTimeSlotInformation { } } +impl Default for GuaranteedTimeSlotInformation { + fn default() -> Self { + Self::new() + } +} + impl TryWrite for GuaranteedTimeSlotInformation { fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result { let offset = &mut 0; @@ -275,9 +287,9 @@ impl TryWrite for GuaranteedTimeSlotInformation { for n in 0..self.slot_count { let slot = self.slots[n]; if slot.direction_transmit() { - direction_mask = direction_mask | dir; + direction_mask |= dir; } - dir = dir << 1; + dir <<= 1; } direction_mask }; @@ -307,7 +319,7 @@ impl TryRead<'_> for GuaranteedTimeSlotInformation { if slot_count > 0 { check_len(&bytes[*offset..], 2 + (3 * slot_count))?; let mut direction_mask: u8 = bytes.read(offset)?; - for n in 0..slot_count { + for slot_target in slots.iter_mut().take(slot_count) { let mut slot: GuaranteedTimeSlotDescriptor = bytes.read(offset)?; let direction = if direction_mask & 0b1 == 0b1 { @@ -316,8 +328,8 @@ impl TryRead<'_> for GuaranteedTimeSlotInformation { Direction::Receive }; slot.set_direction(direction); - direction_mask = direction_mask >> 1; - slots[n] = slot; + direction_mask >>= 1; + *slot_target = slot; } } Ok(( @@ -383,6 +395,12 @@ impl PendingAddress { } } +impl Default for PendingAddress { + fn default() -> Self { + Self::new() + } +} + impl TryRead<'_> for PendingAddress { fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> { let offset = &mut 0; @@ -393,12 +411,12 @@ impl TryRead<'_> for PendingAddress { let el = ((byte & EXTENDED_MASK) >> 4) as usize; check_len(&bytes[*offset..], (sl * ss) + (el * es))?; let mut short_addresses = [ShortAddress::broadcast(); 7]; - for n in 0..sl { - short_addresses[n] = bytes.read(offset)?; + for short_address in short_addresses.iter_mut().take(sl) { + *short_address = bytes.read(offset)?; } let mut extended_addresses = [ExtendedAddress::broadcast(); 7]; - for n in 0..el { - extended_addresses[n] = bytes.read(offset)?; + for extended_address in extended_addresses.iter_mut().take(el) { + *extended_address = bytes.read(offset)?; } Ok(( Self { diff --git a/src/mac/command.rs b/src/mac/command.rs index cc1c76c..1885725 100644 --- a/src/mac/command.rs +++ b/src/mac/command.rs @@ -80,19 +80,19 @@ impl From for u8 { fn from(ar: CapabilityInformation) -> Self { let mut byte = 0u8; if ar.full_function_device { - byte = byte | CAP_FFD; + byte |= CAP_FFD } if ar.mains_power { - byte = byte | CAP_MAINS_POWER; + byte |= CAP_MAINS_POWER } if ar.idle_receive { - byte = byte | CAP_IDLE_RECEIVE; + byte |= CAP_IDLE_RECEIVE } if ar.frame_protection { - byte = byte | CAP_FRAME_PROTECTION; + byte |= CAP_FRAME_PROTECTION } if ar.allocate_address { - byte = byte | CAP_ALLOCATE_ADDRESS; + byte |= CAP_ALLOCATE_ADDRESS } byte } @@ -157,7 +157,7 @@ impl TryWrite for CoordinatorRealignmentData { impl TryRead<'_> for CoordinatorRealignmentData { fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> { let offset = &mut 0; - check_len(&bytes, 7)?; + check_len(bytes, 7)?; let pan_id = bytes.read(offset)?; let coordinator_address = bytes.read(offset)?; let channel = bytes.read(offset)?; @@ -213,10 +213,10 @@ impl From for u8 { fn from(gtsc: GuaranteedTimeSlotCharacteristics) -> Self { let mut byte = gtsc.count & 0x0f; if gtsc.receive_only { - byte = byte | GTSC_RECEIVE_ONLY; + byte |= GTSC_RECEIVE_ONLY } if gtsc.allocation { - byte = byte | GTSC_ALLOCATION; + byte |= GTSC_ALLOCATION; } byte } diff --git a/src/mac/frame/header.rs b/src/mac/frame/header.rs index a8bf7f0..48ee586 100644 --- a/src/mac/frame/header.rs +++ b/src/mac/frame/header.rs @@ -4,18 +4,21 @@ //! //! [`Header`]: struct.Header.html -use byte::{check_len, BytesExt, TryRead, TryWrite, LE}; -use cipher::{consts::U16, BlockCipher, NewBlockCipher}; -use hash32_derive::Hash32; - +use super::frame_control::{mask, offset}; pub use super::frame_control::{AddressMode, FrameType, FrameVersion}; +use super::security::AuxiliarySecurityHeader; +use super::security::SecurityContext; use super::DecodeError; -use super::{ - frame_control::{mask, offset}, - security::{KeyDescriptorLookup, SecurityContext}, +use crate::mac::frame::EncodeError; +#[cfg(not(feature = "security"))] +use crate::mac::frame::FrameSerDesContext; +use byte::{check_len, BytesExt, TryRead, TryWrite, LE}; +use hash32_derive::Hash32; +#[cfg(feature = "security")] +use { + super::security::KeyDescriptorLookup, + cipher::{consts::U16, BlockCipher, NewBlockCipher}, }; -use super::{security::AuxiliarySecurityHeader, EncodeError}; - /// MAC frame header /// /// External documentation for [MAC frame format start at 5.2] @@ -88,18 +91,13 @@ impl Header { // Frame control + sequence number let mut len = 3; - for i in [self.destination, self.source].iter() { - match i { - Some(addr) => { - // pan ID - len += 2; - // Address length - match addr { - Address::Short(..) => len += 2, - Address::Extended(..) => len += 8, - } - } - _ => {} + for addr in [self.destination, self.source].iter().flatten() { + // pan ID + len += 2; + // Address length + match addr { + Address::Short(..) => len += 2, + Address::Extended(..) => len += 8, } } len @@ -115,7 +113,7 @@ impl TryRead<'_> for Header { fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> { let offset = &mut 0; // Make sure we have enough buffer for the Frame Control field - check_len(&bytes, 3)?; + check_len(bytes, 3)?; /* Decode Frame Control Field */ let bits: u16 = bytes.read_with(offset, LE)?; @@ -230,6 +228,7 @@ impl TryRead<'_> for Header { } } +#[cfg(feature = "security")] impl TryWrite<&Option<&mut SecurityContext>> for Header where @@ -306,6 +305,64 @@ where } } +#[cfg(not(feature = "security"))] +impl TryWrite<&Option<&mut SecurityContext>> for Header { + fn try_write( + self, + bytes: &mut [u8], + _sec_ctx: &Option<&mut SecurityContext>, + ) -> byte::Result { + let offset = &mut 0; + let dest_addr_mode = AddressMode::from(self.destination); + let src_addr_mode = AddressMode::from(self.source); + + let security = self.auxiliary_security_header.is_some(); + + let frame_control_raw = (self.frame_type as u16) << offset::FRAME_TYPE + | (security as u16) << offset::SECURITY + | (self.frame_pending as u16) << offset::PENDING + | (self.ack_request as u16) << offset::ACK + | (self.pan_id_compress as u16) << offset::PAN_ID_COMPRESS + | (dest_addr_mode as u16) << offset::DEST_ADDR_MODE + | (self.version as u16) << offset::VERSION + | (src_addr_mode as u16) << offset::SRC_ADDR_MODE; + + bytes.write_with(offset, frame_control_raw, LE)?; + + // Write Sequence Number + bytes.write(offset, self.seq)?; + + if (self.destination.is_none() || self.source.is_none()) + && self.pan_id_compress + { + return Err(EncodeError::DisallowedPanIdCompress)?; + } + + // Write addresses + if let Some(destination) = self.destination { + bytes.write_with(offset, destination, AddressEncoding::Normal)?; + } + + match (self.source, self.pan_id_compress) { + (Some(source), true) => { + bytes.write_with( + offset, + source, + AddressEncoding::Compressed, + )?; + } + (Some(source), false) => { + bytes.write_with(offset, source, AddressEncoding::Normal)?; + } + (None, true) => { + panic!("frame control request compress source address without contain this address") + } + (None, false) => (), + } + Ok(*offset) + } +} + /// Personal Area Network Identifier /// /// A 16-bit value that identifies a PAN diff --git a/src/mac/frame/mod.rs b/src/mac/frame/mod.rs index e290f8c..7cc78c9 100644 --- a/src/mac/frame/mod.rs +++ b/src/mac/frame/mod.rs @@ -17,15 +17,18 @@ use crate::mac::command::Command; mod frame_control; pub mod header; pub mod security; -use byte::{ctx::Bytes, BytesExt, TryRead, TryWrite, LE}; +use byte::{ctx::Bytes, BytesExt, Error, TryRead, TryWrite, LE}; +#[cfg(feature = "security")] use ccm::aead::generic_array::typenum::consts::U16; +#[cfg(feature = "security")] use cipher::{BlockCipher, BlockEncrypt, NewBlockCipher}; use header::FrameType; pub use header::Header; +use self::security::{default::Unimplemented, SecurityContext}; +#[cfg(feature = "security")] use self::security::{ - default::Unimplemented, DeviceDescriptorLookup, KeyDescriptorLookup, - SecurityContext, SecurityError, + DeviceDescriptorLookup, KeyDescriptorLookup, SecurityError, }; /// An IEEE 802.15.4 MAC frame @@ -50,7 +53,6 @@ use self::security::{ /// FrameType, /// FooterMode, /// PanId, -/// FrameSerDesContext, /// }; /// use byte::BytesExt; /// @@ -108,7 +110,7 @@ use self::security::{ /// FrameVersion, /// Header, /// PanId, -/// FrameSerDesContext, +/// frame::FrameSerDesContext /// }; /// use byte::BytesExt; /// @@ -136,7 +138,7 @@ use self::security::{ /// let mut bytes = [0u8; 32]; /// let mut len = 0usize; /// -/// bytes.write_with(&mut len, frame, &mut FrameSerDesContext::no_security(FooterMode::Explicit)).unwrap(); +/// bytes.write_with(&mut len, frame, &mut FrameSerDesContext::no_security(FooterMode::Explicit)).unwrap(); /// /// let expected_bytes = [ /// 0x01, 0x98, // frame control @@ -176,6 +178,7 @@ pub struct Frame<'p> { /// A context that is used for serializing and deserializing frames, which also /// stores the frame counter +#[cfg(feature = "security")] pub struct FrameSerDesContext<'a, AEADBLKCIPH, KEYDESCLO> where AEADBLKCIPH: NewBlockCipher + BlockCipher, @@ -187,6 +190,7 @@ where security_ctx: Option<&'a mut SecurityContext>, } +#[cfg(feature = "security")] impl<'a, AEADBLKCIPH, KEYDESCLO> FrameSerDesContext<'a, AEADBLKCIPH, KEYDESCLO> where AEADBLKCIPH: NewBlockCipher + BlockCipher, @@ -205,6 +209,28 @@ where } } +#[cfg(not(feature = "security"))] +/// A context that is used for serializing and deserializing frames, which also +/// stores the frame counter +pub struct FrameSerDesContext<'a> { + /// The footer mode to use when handling frames + footer_mode: FooterMode, + /// The security context for handling frames (if any) + security_ctx: Option<&'a mut SecurityContext>, +} +#[cfg(not(feature = "security"))] +impl FrameSerDesContext<'_> { + /// Create a new frame serialization/deserialization context with the specified footer mode, + /// that does not facilitate any security functionality + pub fn no_security(mode: FooterMode) -> Self { + FrameSerDesContext { + footer_mode: mode, + security_ctx: None, + } + } +} + +#[cfg(feature = "security")] impl FrameSerDesContext<'_, Unimplemented, Unimplemented> { /// Create a new frame serialization/deserialization context with the specified footer mode, /// that does not facilitate any security functionality @@ -216,6 +242,7 @@ impl FrameSerDesContext<'_, Unimplemented, Unimplemented> { } } +#[cfg(feature = "security")] impl TryWrite<&mut FrameSerDesContext<'_, AEADBLKCIPH, KEYDESCLO>> for Frame<'_> where @@ -268,6 +295,35 @@ where } } +#[cfg(not(feature = "security"))] +impl TryWrite<&mut FrameSerDesContext<'_>> for Frame<'_> { + fn try_write( + self, + bytes: &mut [u8], + context: &mut FrameSerDesContext, + ) -> byte::Result { + let mode = context.footer_mode; + let offset = &mut 0; + + bytes.write_with(offset, self.header, &context.security_ctx)?; + bytes.write(offset, self.content)?; + + let security_enabled = false; + + if !security_enabled { + bytes.write(offset, self.payload.as_ref())?; + } + + match mode { + FooterMode::None => {} + // TODO: recalculate the footer after encryption? + FooterMode::Explicit => bytes.write(offset, &self.footer[..])?, + } + + Ok(*offset) + } +} + impl<'a> Frame<'a> { /// Try to read a frame. If the frame is secured, it will be unsecured /// @@ -277,6 +333,7 @@ impl<'a> Frame<'a> { /// /// Use [`FrameSerDesContext::no_security`] and/or [`Unimplemented`] if you /// do not want to use any security, or simply [`Frame::try_read`] + #[cfg(feature = "security")] pub fn try_read_and_unsecure( buf: &'a mut [u8], ctx: &mut FrameSerDesContext<'_, AEADBLKCIPH, KEYDESCLO>, @@ -553,9 +610,8 @@ impl From for byte::Error { #[cfg(test)] mod tests { - use crate::mac::beacon; - use crate::mac::command; use crate::mac::frame::*; + use crate::mac::{beacon, command}; use crate::mac::{ Address, ExtendedAddress, FrameVersion, PanId, ShortAddress, }; @@ -644,6 +700,7 @@ mod tests { assert_eq!(frame.payload.len(), 3); } + #[cfg(not(feature = "security"))] #[test] fn encode_ver0_short() { let frame = Frame { @@ -688,6 +745,7 @@ mod tests { ); } + #[cfg(not(feature = "security"))] #[test] fn encode_ver1_extended() { let frame = Frame { @@ -745,6 +803,7 @@ mod tests { ); } + #[cfg(not(feature = "security"))] #[test] fn encode_ver0_pan_compress() { let frame = Frame { @@ -789,6 +848,7 @@ mod tests { ); } + #[cfg(not(feature = "security"))] #[test] fn encode_ver2_none() { let frame = Frame { @@ -827,6 +887,7 @@ mod tests { ); } + #[cfg(feature = "security")] #[test] fn empty_addressing_and_panid_compress() { let mut frame_data = [0u8; 127]; diff --git a/src/mac/frame/security/auxiliary_security_header.rs b/src/mac/frame/security/auxiliary_security_header.rs index 1e771f2..514745d 100644 --- a/src/mac/frame/security/auxiliary_security_header.rs +++ b/src/mac/frame/security/auxiliary_security_header.rs @@ -1,9 +1,10 @@ //! All auxiliary security header structs and functions -use super::{ - KeyDescriptorLookup, KeyIdentifierMode, SecurityContext, SecurityControl, -}; +#[cfg(feature = "security")] +use super::{KeyDescriptorLookup, SecurityContext}; +use super::{KeyIdentifierMode, SecurityControl}; use byte::{BytesExt, TryRead, TryWrite, LE}; +#[cfg(feature = "security")] use cipher::{consts::U16, BlockCipher, NewBlockCipher}; /// A struct describing the Auxiliary Security Header @@ -25,8 +26,7 @@ impl AuxiliarySecurityHeader { /// Get the size of this security header, in octets pub fn get_octet_size(&self) -> usize { // SecurityControl length + FrameCounter length - let length = 1 - + 4 + 1 + 4 + match self.key_identifier { Some(key_id) => match key_id.key_source { Some(source) => match source { @@ -36,8 +36,7 @@ impl AuxiliarySecurityHeader { None => 1, }, None => 0, - }; - length + } } /// Create a new Auxiliary Security Header with the specified control and key identifier @@ -54,6 +53,7 @@ impl AuxiliarySecurityHeader { /// Create a new Auxiliary Security Header with the specified control, key identifier, and frame counter. /// + /// # Safety /// This function is unsafe because the frame_counter is almost always set when parsing a frame from a buffer, /// or by the security context at the time of actually writing a secured frame. pub unsafe fn new_unsafe( @@ -115,6 +115,7 @@ impl TryRead<'_> for AuxiliarySecurityHeader { } } +#[cfg(feature = "security")] impl TryWrite<&SecurityContext> for AuxiliarySecurityHeader where @@ -143,11 +144,8 @@ where bytes.write(offset, self.control)?; bytes.write(offset, sec_ctx.frame_counter)?; - match self.key_identifier { - Some(key_identifier) => { - bytes.write(offset, key_identifier)?; - } - _ => {} + if let Some(key_identifier) = self.key_identifier { + bytes.write(offset, key_identifier)?; } Ok(*offset) } @@ -166,12 +164,11 @@ pub struct KeyIdentifier { impl TryWrite for KeyIdentifier { fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result { let offset = &mut 0; - match self.key_source { - Some(source) => match source { + if let Some(source) = self.key_source { + match source { KeySource::Short(src) => bytes.write(offset, src)?, KeySource::Long(src) => bytes.write(offset, src)?, - }, - _ => {} + } } bytes.write(offset, self.key_index)?; diff --git a/src/mac/frame/security/default.rs b/src/mac/frame/security/default.rs index d54542a..aed086f 100644 --- a/src/mac/frame/security/default.rs +++ b/src/mac/frame/security/default.rs @@ -3,22 +3,27 @@ use super::{ auxiliary_security_header::KeyIdentifier, AddressingMode, DeviceDescriptor, - DeviceDescriptorLookup, KeyDescriptorLookup, + DeviceDescriptorLookup, }; use crate::mac::Address; -use ccm::aead::generic_array::{ - typenum::consts::{U1, U16}, - GenericArray, -}; -use cipher::{ - Block, BlockCipher, BlockCipherKey, BlockDecrypt, BlockEncrypt, - NewBlockCipher, +#[cfg(feature = "security")] +use { + super::KeyDescriptorLookup, + ccm::aead::generic_array::{ + typenum::consts::{U1, U16}, + GenericArray, + }, + cipher::{ + Block, BlockCipher, BlockCipherKey, BlockDecrypt, BlockEncrypt, + NewBlockCipher, + }, }; /// A struct that fullfills all of the trait bounds for serialization and deserializtion, but is not /// actually capable of performing any of the operations pub struct Unimplemented; +#[cfg(feature = "security")] impl KeyDescriptorLookup for Unimplemented { fn lookup_key_descriptor( &self, @@ -30,20 +35,24 @@ impl KeyDescriptorLookup for Unimplemented { } } +#[cfg(feature = "security")] impl BlockCipher for Unimplemented { type BlockSize = U16; type ParBlocks = U1; } +#[cfg(feature = "security")] impl BlockEncrypt for Unimplemented { fn encrypt_block(&self, _block: &mut Block) {} } +#[cfg(feature = "security")] impl BlockDecrypt for Unimplemented { fn decrypt_block(&self, _block: &mut Block) {} } +#[cfg(feature = "security")] impl NewBlockCipher for Unimplemented { type KeySize = U16; diff --git a/src/mac/frame/security/mod.rs b/src/mac/frame/security/mod.rs index 52d878f..a218691 100644 --- a/src/mac/frame/security/mod.rs +++ b/src/mac/frame/security/mod.rs @@ -4,8 +4,8 @@ //! //! # Example on how to use frames with security //! Note that the example below is _very insecure_, and should not be used in any production setting -//! -//! ```rust +#![cfg_attr(not(feature = "security"), doc = "```ignore")] +#![cfg_attr(feature = "security", doc = "```rust")] //! use ieee802154::mac::{ //! frame::security::{ //! KeyDescriptorLookup, @@ -164,10 +164,10 @@ pub mod default; mod security_control; use self::default::Unimplemented; - use super::{FooterMode, Frame, Header}; use crate::mac::{Address, FrameType, FrameVersion}; use byte::BytesExt; +#[cfg(feature = "security")] use ccm::{ aead::{ generic_array::{ @@ -183,6 +183,7 @@ use core::marker::PhantomData; pub use auxiliary_security_header::{ AuxiliarySecurityHeader, KeyIdentifier, KeySource, }; +#[cfg(feature = "security")] pub use cipher::{ generic_array::typenum::consts::U16, BlockCipher, BlockEncrypt, NewBlockCipher, @@ -207,6 +208,7 @@ pub struct DeviceDescriptor { pub exempt: bool, } +#[cfg(feature = "security")] /// Used to create a KeyDescriptor from a KeyIdentifier and device address pub trait KeyDescriptorLookup where @@ -249,6 +251,7 @@ pub trait DeviceDescriptorLookup { /// /// NONCEGEN is the type that will convert the nonce created using the 802.15.4 standard /// into a nonce of the size that can be accepted by the provided AEAD algorithm +#[cfg(feature = "security")] #[derive(Clone, Copy)] pub struct SecurityContext where @@ -268,6 +271,12 @@ where phantom_data: PhantomData, } +#[cfg(not(feature = "security"))] +/// A blank context for when no security is used, but we still want the same API +#[derive(Clone, Copy)] +pub struct SecurityContext {} + +#[cfg(feature = "security")] impl SecurityContext where AEADBLKCIPH: NewBlockCipher + BlockCipher, @@ -285,6 +294,7 @@ where } } +#[cfg(feature = "security")] impl SecurityContext { /// A security context that is not actually capable of providing any security pub fn no_security() -> Self { @@ -297,14 +307,15 @@ impl SecurityContext { } } +#[cfg(feature = "security")] fn calculate_nonce( source_addr: u64, frame_counter: u32, sec_level: SecurityLevel, ) -> [u8; 13] { let mut output = [0u8; 13]; - for i in 0..8 { - output[i] = (source_addr >> (8 * i) & 0xFF) as u8; + for (i, output) in output.iter_mut().enumerate().take(8) { + *output = (source_addr >> (8 * i) & 0xFF) as u8; } for i in 0..4 { @@ -326,7 +337,8 @@ fn calculate_nonce( /// /// # Panics /// if footer_mode is not None due to currently absent implementation of explicit footers -pub(crate) fn secure_frame<'a, AEADBLKCIPH, KEYDESCLO>( +#[cfg(feature = "security")] +pub(crate) fn secure_frame( frame: Frame<'_>, context: &mut SecurityContext, footer_mode: FooterMode, @@ -347,7 +359,7 @@ where } } - let mut offset = 0 as usize; + let mut offset = 0; let header = frame.header; if header.has_security() { @@ -368,12 +380,12 @@ where // If frame size plus AuthLen plus AuxLen plus FCS is bigger than aMaxPHYPacketSize // 7.2.1b4 - if !(frame.payload.len() + if frame.payload.len() + frame.header.get_octet_size() + aux_len + auth_len + 2 - <= 127) + > 127 { return Err(SecurityError::FrameTooLong); } @@ -482,15 +494,15 @@ where #[allow(unreachable_patterns)] _ => {} }; - return Ok(offset); + Ok(offset) } else { - return Err(SecurityError::UnavailableKey); + Err(SecurityError::UnavailableKey) } } else { - return Err(SecurityError::AuxSecHeaderAbsent); + Err(SecurityError::AuxSecHeaderAbsent) } } else { - return Err(SecurityError::SecurityNotEnabled); + Err(SecurityError::SecurityNotEnabled) } } @@ -510,7 +522,8 @@ where /// /// # Panics /// if footer_mode is not None due to currently absent implementation of explicit footers -pub(crate) fn unsecure_frame<'a, AEADBLKCIPH, KEYDESCLO, DEVDESCLO>( +#[cfg(feature = "security")] +pub(crate) fn unsecure_frame( header: &Header, buffer: &mut [u8], context: &mut SecurityContext, @@ -670,9 +683,9 @@ where } else { return Err(SecurityError::UnavailableKey); } - return Ok(taglen); + Ok(taglen) } else { - return Err(SecurityError::SecurityNotEnabled); + Err(SecurityError::SecurityNotEnabled) } } @@ -789,6 +802,7 @@ impl From for byte::Error { } #[cfg(test)] +#[cfg(feature = "security")] mod tests { use crate::mac::frame::header::*; use crate::mac::frame::security::{security_control::*, *}; @@ -816,6 +830,7 @@ mod tests { } } } + struct BasicDevDescriptorLookup<'a> { descriptor: &'a mut DeviceDescriptor, } @@ -990,31 +1005,38 @@ mod tests { fn test_enc() { test_security_level!(SecurityLevel::ENC); } + #[test] fn test_mic32() { test_security_level!(SecurityLevel::MIC32); } + #[test] fn test_mic64() { test_security_level!(SecurityLevel::MIC64); } + #[test] fn test_mic128() { test_security_level!(SecurityLevel::MIC128); } + #[test] fn test_encmic32() { test_security_level!(SecurityLevel::ENCMIC32); } + #[test] fn test_encmic64() { test_security_level!(SecurityLevel::ENCMIC64); } + #[test] fn test_encmic128() { test_security_level!(SecurityLevel::ENCMIC128); } + #[cfg(not(feature = "security"))] #[test] fn encode_decode_secured_frame() { let source_euid = 0x08; diff --git a/src/mac/frame/security/security_control.rs b/src/mac/frame/security/security_control.rs index dbca01b..891f346 100644 --- a/src/mac/frame/security/security_control.rs +++ b/src/mac/frame/security/security_control.rs @@ -101,6 +101,7 @@ impl SecurityLevel { } } + #[allow(clippy::wrong_self_convention)] pub(crate) fn to_bits(&self) -> u8 { match self { SecurityLevel::None => 0b000, @@ -150,6 +151,7 @@ impl KeyIdentifierMode { _ => None, } } + #[allow(clippy::wrong_self_convention)] fn to_bits(&self) -> u8 { match self { KeyIdentifierMode::None => 0b00, diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 51ed3e5..fbec3de 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -4,10 +4,10 @@ pub mod beacon; pub mod command; pub mod frame; +#[cfg(feature = "security")] +pub use crate::mac::frame::FrameSerDesContext; pub use frame::header::{ Address, AddressMode, ExtendedAddress, FrameType, FrameVersion, Header, PanId, ShortAddress, }; -pub use frame::{ - security, DecodeError, FooterMode, Frame, FrameContent, FrameSerDesContext, -}; +pub use frame::{security, DecodeError, FooterMode, Frame, FrameContent}; diff --git a/src/utils.rs b/src/utils.rs index 1225f73..553e74a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -48,19 +48,5 @@ macro_rules! extended_enum { } } } - - impl PartialEq<$name> for $ty { - fn eq(&self, other: &$name) -> bool { - match *other { - $( $name::$var => *self == $val, )* - } - } - - fn ne(&self, other: &$name) -> bool { - match *other { - $( $name::$var => *self != $val, )* - } - } - } ); }