1use core::borrow::Borrow;
19use core::future::Future;
20use core::mem::MaybeUninit;
21
22use num_derive::FromPrimitive;
23
24use crate::crypto::Crypto;
25use crate::dm::AttrChangeNotifier;
26use crate::error::{Error, ErrorCode};
27use crate::respond::ExchangeHandler;
28use crate::tlv::{FromTLV, ToTLV};
29use crate::transport::exchange::{Exchange, MessageMeta};
30use crate::utils::init::InitMaybeUninit;
31use crate::utils::storage::{ReadBuf, WriteBuf};
32
33use case::CaseResponder;
34use pase::PaseResponder;
35
36pub mod busy;
37pub mod case;
38pub mod pase;
39
40pub const PROTO_ID_SECURE_CHANNEL: u16 = 0x00;
42
43#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub enum OpCode {
46 MsgCounterSyncReq = 0x00,
47 MsgCounterSyncResp = 0x01,
48 MRPStandAloneAck = 0x10,
49 PBKDFParamRequest = 0x20,
50 PBKDFParamResponse = 0x21,
51 PASEPake1 = 0x22,
52 PASEPake2 = 0x23,
53 PASEPake3 = 0x24,
54 CASESigma1 = 0x30,
55 CASESigma2 = 0x31,
56 CASESigma3 = 0x32,
57 CASESigma2Resume = 0x33,
58 StatusReport = 0x40,
59}
60
61impl OpCode {
62 pub fn meta(&self) -> MessageMeta {
63 MessageMeta {
64 proto_id: PROTO_ID_SECURE_CHANNEL,
65 proto_opcode: *self as u8,
66 reliable: !matches!(self, Self::MRPStandAloneAck),
67 }
68 }
69
70 pub fn is_tlv(&self) -> bool {
71 !matches!(
72 self,
73 Self::MRPStandAloneAck
74 | Self::StatusReport
75 | Self::MsgCounterSyncReq
76 | Self::MsgCounterSyncResp
77 )
78 }
79}
80
81impl From<OpCode> for MessageMeta {
82 fn from(op: OpCode) -> Self {
83 op.meta()
84 }
85}
86
87#[derive(Debug, Copy, Clone, PartialEq, Eq)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub enum SCStatusCodes {
90 SessionEstablishmentSuccess = 0,
91 NoSharedTrustRoots = 1,
92 InvalidParameter = 2,
93 CloseSession = 3,
94 Busy = 4,
95 SessionNotFound = 5,
96}
97
98impl SCStatusCodes {
99 pub fn reliable(&self) -> bool {
100 !matches!(
102 self,
103 SCStatusCodes::CloseSession | SCStatusCodes::Busy | SCStatusCodes::SessionNotFound
104 )
105 }
106
107 pub fn as_report<'a>(&self, payload: &'a [u8]) -> StatusReport<'a> {
108 let general_code = match self {
109 SCStatusCodes::SessionEstablishmentSuccess => GeneralCode::Success,
110 SCStatusCodes::CloseSession => GeneralCode::Success,
111 SCStatusCodes::Busy => GeneralCode::Busy,
112 SCStatusCodes::InvalidParameter
113 | SCStatusCodes::NoSharedTrustRoots
114 | SCStatusCodes::SessionNotFound => GeneralCode::Failure,
115 };
116
117 StatusReport {
118 general_code,
119 proto_id: PROTO_ID_SECURE_CHANNEL as u32,
120 proto_code: *self as u16,
121 proto_data: payload,
122 }
123 }
124}
125
126pub async fn complete_with_status(
127 exchange: &mut Exchange<'_>,
128 status_code: SCStatusCodes,
129 payload: &[u8],
130) -> Result<(), Error> {
131 exchange
132 .send_with(|_, wb| sc_write(wb, status_code, payload))
133 .await
134}
135
136pub fn sc_write(
137 wb: &mut WriteBuf,
138 status_code: SCStatusCodes,
139 payload: &[u8],
140) -> Result<Option<MessageMeta>, Error> {
141 status_code.as_report(payload).write(wb)?;
142
143 Ok(Some(
144 OpCode::StatusReport.meta().reliable(status_code.reliable()),
145 ))
146}
147
148#[allow(dead_code)]
149#[derive(FromPrimitive, PartialEq, Eq, Debug, Copy, Clone)]
150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151pub enum GeneralCode {
152 Success = 0,
153 Failure = 1,
154 BadPrecondition = 2,
155 OutOfRange = 3,
156 BadRequest = 4,
157 Unsupported = 5,
158 Unexpected = 6,
159 ResourceExhausted = 7,
160 Busy = 8,
161 Timeout = 9,
162 Continue = 10,
163 Aborted = 11,
164 InvalidArgument = 12,
165 NotFound = 13,
166 AlreadyExists = 14,
167 PermissionDenied = 15,
168 DataLoss = 16,
169}
170
171#[derive(Default, FromTLV, ToTLV, Debug)]
174#[cfg_attr(feature = "defmt", derive(defmt::Format))]
175#[tlvargs(start = 1)]
176pub(crate) struct SessionParameters {
177 pub(crate) sii: Option<u32>,
179 pub(crate) sai: Option<u32>,
181 pub(crate) sat: Option<u16>,
183 pub(crate) dm_revision: Option<u16>,
185 pub(crate) im_revision: Option<u16>,
187 pub(crate) spec_version: Option<u32>,
189 pub(crate) max_paths_per_invoke: Option<u16>,
191}
192
193#[derive(Debug, Clone)]
195#[cfg_attr(feature = "defmt", derive(defmt::Format))]
196pub struct StatusReport<'a> {
197 pub general_code: GeneralCode,
198 pub proto_id: u32,
199 pub proto_code: u16,
200 pub proto_data: &'a [u8],
201}
202
203impl<'a> StatusReport<'a> {
204 pub fn read<T>(pb: &'a mut ReadBuf<T>) -> Result<Self, Error>
205 where
206 T: Borrow<[u8]>,
207 {
208 Ok(Self {
209 general_code: num::FromPrimitive::from_u16(pb.le_u16()?)
210 .ok_or(ErrorCode::InvalidOpcode)?,
211 proto_id: pb.le_u32()?,
212 proto_code: pb.le_u16()?,
213 proto_data: pb.as_slice(),
214 })
215 }
216
217 pub fn write(&self, wb: &mut WriteBuf) -> Result<(), Error> {
218 wb.le_u16(self.general_code as u16)?;
219 wb.le_u32(self.proto_id)?;
220 wb.le_u16(self.proto_code)?;
221 wb.copy_from_slice(self.proto_data)?;
222
223 Ok(())
224 }
225}
226
227pub struct SecureChannel<'a, C> {
229 crypto: C,
230 notify: &'a dyn AttrChangeNotifier,
231}
232
233impl<'a, C: Crypto> SecureChannel<'a, C> {
234 #[inline(always)]
235 pub const fn new(crypto: C, notify: &'a dyn AttrChangeNotifier) -> Self {
236 Self { crypto, notify }
237 }
238
239 pub async fn handle(&self, mut exchange: Exchange<'_>) -> Result<(), Error> {
240 if exchange.rx().is_err() {
241 exchange.recv_fetch().await?;
242 }
243
244 let meta = exchange.rx()?.meta();
245 if meta.proto_id != PROTO_ID_SECURE_CHANNEL {
246 Err(ErrorCode::InvalidProto)?;
247 }
248
249 match meta.opcode()? {
250 OpCode::PBKDFParamRequest => {
251 let mut pase = MaybeUninit::uninit(); pase.init_with(PaseResponder::init(&self.crypto, self.notify))
253 .handle(&mut exchange)
254 .await
255 }
256 OpCode::CASESigma1 => {
257 let mut case = MaybeUninit::uninit(); case.init_with(CaseResponder::init(&self.crypto))
259 .handle(&mut exchange)
260 .await
261 }
262 opcode => {
263 error!("Invalid opcode: {:?}", opcode);
264 Err(ErrorCode::InvalidOpcode.into())
265 }
266 }
267 }
268}
269
270impl<C: Crypto> ExchangeHandler for SecureChannel<'_, C> {
271 fn handle(&self, exchange: Exchange<'_>) -> impl Future<Output = Result<(), Error>> {
272 SecureChannel::handle(self, exchange)
273 }
274}
275
276fn check_opcode(exchange: &Exchange<'_>, opcode: OpCode) -> Result<(), Error> {
280 let meta = exchange.rx()?.meta();
281 let their_opcode = meta.opcode::<OpCode>()?;
282
283 if their_opcode == opcode {
284 Ok(())
285 } else {
286 error!("Invalid opcode: {:?}, expected: {:?}", their_opcode, opcode);
287
288 if matches!(their_opcode, OpCode::StatusReport) {
289 let mut rb = ReadBuf::new(exchange.rx()?.payload());
290
291 match StatusReport::read(&mut rb) {
293 Ok(status_report) => error!("Status Report: {:?}", status_report),
294 Err(e) => error!("Failed to parse Status Report: {:?}", e),
295 }
296 }
297
298 Err(ErrorCode::Invalid.into())
299 }
300}