Skip to content

Commit c675f91

Browse files
Replace iso7816::Command with iso7816::command::CommandView
This allows us to drop one generic parameter from the App trait and potentially generate more efficient code.
1 parent 6994b0a commit c675f91

File tree

7 files changed

+50
-43
lines changed

7 files changed

+50
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ license = "Apache-2.0 OR MIT"
99
repository = "https://github.com/trussed-dev/apdu-dispatch"
1010

1111
[workspace.dependencies]
12-
iso7816 = "0.1.1"
12+
iso7816 = "0.1.2"
1313

1414
[patch.crates-io]
1515
apdu-app.path = "app"

app/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [Unreleased]
88

99
- Extract `app` module from `apdu-dispatch` 0.2.0 into a separate crate.
10+
- Replace `iso7816::Command` with `iso7816::command::CommandView` in the `App` trait and remove the `C` parameter.

app/src/lib.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
#![no_std]
22

3-
pub use iso7816::{Command, Data, Interface, Status};
3+
pub use iso7816::{command::CommandView, Data, Interface, Status};
44

55
pub type Result = iso7816::Result<()>;
66

77
/// An App can receive and respond APDUs at behest of the ApduDispatch.
8-
pub trait App<const C: usize, const R: usize>: iso7816::App {
8+
pub trait App<const R: usize>: iso7816::App {
99
/// Given parsed APDU for select command.
1010
/// Write response data back to buf, and return length of payload. Return APDU Error code on error.
1111
/// Alternatively, the app can defer the response until later by returning it in `poll()`.
12-
fn select(&mut self, interface: Interface, apdu: &Command<C>, reply: &mut Data<R>) -> Result;
12+
fn select(
13+
&mut self,
14+
interface: Interface,
15+
apdu: CommandView<'_>,
16+
reply: &mut Data<R>,
17+
) -> Result;
1318

1419
/// Deselects the app. This is the result of another app getting selected.
1520
/// App should clear any sensitive state and reset security indicators.
1621
fn deselect(&mut self);
1722

1823
/// Given parsed APDU for app when selected.
1924
/// Write response data back to buf, and return length of payload. Return APDU Error code on error.
20-
fn call(&mut self, interface: Interface, apdu: &Command<C>, reply: &mut Data<R>) -> Result;
25+
fn call(&mut self, interface: Interface, apdu: CommandView<'_>, reply: &mut Data<R>) -> Result;
2126
}

dispatch/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [Unreleased]
88

99
- Move the `app` module into a separate crate, `apdu-app`, and re-export it.
10+
- Replace `iso7816::Command` with `iso7816::command::CommandView` in the `App` trait and remove the `C` parameter.
1011

1112
## [0.2.0]
1213

dispatch/src/dispatch.rs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@
88
//!
99
//! Apps need to implement the App trait to be managed.
1010
//!
11-
use crate::command::SIZE as CommandSize;
1211
use crate::response::SIZE as ResponseSize;
1312
use crate::App;
1413
use crate::{
1514
interchanges::{self, Responder},
1615
response, Command,
1716
};
1817

19-
use iso7816::{command::FromSliceError, Aid, Instruction, Result, Status};
18+
use iso7816::{
19+
command::{CommandView, FromSliceError},
20+
Aid, Instruction, Result, Status,
21+
};
2022

2123
/// Maximum length of a data field of a response that can fit in an interchange message after
2224
/// concatenation of SW1SW2
@@ -50,17 +52,17 @@ struct ApduBuffer {
5052
}
5153

5254
impl ApduBuffer {
53-
fn request<const S: usize>(&mut self, command: &iso7816::Command<S>) {
55+
fn request(&mut self, command: CommandView<'_>) {
5456
match &mut self.raw {
5557
RawApduBuffer::Request(buffered) => {
56-
buffered.extend_from_command(command).ok();
58+
buffered.extend_from_command_view(command).ok();
5759
}
5860
_ => {
5961
if self.raw != RawApduBuffer::None {
6062
info!("Was buffering the last response, but aborting that now for this new request.");
6163
}
6264
let mut new_cmd = iso7816::Command::try_from(&[0, 0, 0, 0]).unwrap();
63-
new_cmd.extend_from_command(command).ok();
65+
new_cmd.extend_from_command_view(command).ok();
6466
self.raw = RawApduBuffer::Request(new_cmd);
6567
}
6668
}
@@ -84,7 +86,7 @@ pub struct ApduDispatch<'pipe> {
8486
}
8587

8688
impl<'pipe> ApduDispatch<'pipe> {
87-
fn apdu_type<const S: usize>(apdu: &iso7816::Command<S>, interface: Interface) -> RequestType {
89+
fn apdu_type(apdu: CommandView<'_>, interface: Interface) -> RequestType {
8890
info!("instruction: {:?} {}", apdu.instruction(), apdu.p1);
8991
if apdu.instruction() == Instruction::Select && (apdu.p1 & 0x04) != 0 {
9092
Aid::try_new(apdu.data()).map_or_else(
@@ -119,8 +121,8 @@ impl<'pipe> ApduDispatch<'pipe> {
119121
// but that won't work due to ownership rules
120122
fn find_app<'a, 'b>(
121123
aid: Option<&Aid>,
122-
apps: &'a mut [&'b mut dyn App<CommandSize, ResponseSize>],
123-
) -> Option<&'a mut &'b mut dyn App<CommandSize, ResponseSize>> {
124+
apps: &'a mut [&'b mut dyn App<ResponseSize>],
125+
) -> Option<&'a mut &'b mut dyn App<ResponseSize>> {
124126
// match aid {
125127
// Some(aid) => apps.iter_mut().find(|app| aid.starts_with(app.rid())),
126128
// None => None,
@@ -145,9 +147,9 @@ impl<'pipe> ApduDispatch<'pipe> {
145147
}
146148

147149
#[inline(never)]
148-
fn buffer_chained_apdu_if_needed<const S: usize>(
150+
fn buffer_chained_apdu_if_needed(
149151
&mut self,
150-
command: iso7816::Command<S>,
152+
command: CommandView<'_>,
151153
interface: Interface,
152154
) -> RequestType {
153155
// iso 7816-4 5.1.1
@@ -156,7 +158,7 @@ impl<'pipe> ApduDispatch<'pipe> {
156158
let is_chaining = matches!(self.buffer.raw, RawApduBuffer::Request(_));
157159

158160
if is_chaining {
159-
self.buffer.request(&command);
161+
self.buffer.request(command);
160162

161163
// Response now needs to be chained.
162164
self.was_request_chained = true;
@@ -167,12 +169,12 @@ impl<'pipe> ApduDispatch<'pipe> {
167169
if self.buffer.raw == RawApduBuffer::None {
168170
self.was_request_chained = false;
169171
}
170-
let apdu_type = Self::apdu_type(&command, interface);
172+
let apdu_type = Self::apdu_type(command, interface);
171173
match apdu_type {
172174
// Keep buffer the same in case of GetResponse
173175
RequestType::GetResponse => (),
174176
// Overwrite for everything else.
175-
_ => self.buffer.request(&command),
177+
_ => self.buffer.request(command),
176178
}
177179
apdu_type
178180
}
@@ -193,7 +195,7 @@ impl<'pipe> ApduDispatch<'pipe> {
193195

194196
if !command.data().is_empty() {
195197
info!("chaining {} bytes", command.data().len());
196-
self.buffer.request(&command);
198+
self.buffer.request(command);
197199
}
198200

199201
// Nothing for the application to consume yet.
@@ -259,7 +261,7 @@ impl<'pipe> ApduDispatch<'pipe> {
259261
Ok(command) => {
260262
self.response_len_expected = command.expected();
261263
// The Apdu may be standalone or part of a chain.
262-
self.buffer_chained_apdu_if_needed(command, interface)
264+
self.buffer_chained_apdu_if_needed(command.as_view(), interface)
263265
}
264266
Err(response) => {
265267
// If not a valid APDU, return error and don't pass to app.
@@ -364,7 +366,7 @@ impl<'pipe> ApduDispatch<'pipe> {
364366
#[inline(never)]
365367
fn handle_app_select(
366368
&mut self,
367-
apps: &mut [&mut dyn App<CommandSize, ResponseSize>],
369+
apps: &mut [&mut dyn App<ResponseSize>],
368370
aid: Aid,
369371
interface: Interface,
370372
) {
@@ -393,7 +395,9 @@ impl<'pipe> ApduDispatch<'pipe> {
393395
info!("Selected app");
394396
let mut response = response::Data::new();
395397
let result = match &self.buffer.raw {
396-
RawApduBuffer::Request(apdu) => app.select(interface, apdu, &mut response),
398+
RawApduBuffer::Request(apdu) => {
399+
app.select(interface, apdu.as_view(), &mut response)
400+
}
397401
_ => panic!("Unexpected buffer state."),
398402
};
399403

@@ -409,14 +413,14 @@ impl<'pipe> ApduDispatch<'pipe> {
409413
#[inline(never)]
410414
fn handle_app_command(
411415
&mut self,
412-
apps: &mut [&mut dyn App<CommandSize, ResponseSize>],
416+
apps: &mut [&mut dyn App<ResponseSize>],
413417
interface: Interface,
414418
) {
415419
// if there is a selected app, send it the command
416420
let mut response = response::Data::new();
417421
if let Some(app) = Self::find_app(self.current_aid.as_ref(), apps) {
418422
let result = match &self.buffer.raw {
419-
RawApduBuffer::Request(apdu) => app.call(interface, apdu, &mut response),
423+
RawApduBuffer::Request(apdu) => app.call(interface, apdu.as_view(), &mut response),
420424
_ => panic!("Unexpected buffer state."),
421425
};
422426
self.handle_app_response(&result, &response);
@@ -426,10 +430,7 @@ impl<'pipe> ApduDispatch<'pipe> {
426430
};
427431
}
428432

429-
pub fn poll(
430-
&mut self,
431-
apps: &mut [&mut dyn App<CommandSize, ResponseSize>],
432-
) -> Option<Interface> {
433+
pub fn poll(&mut self, apps: &mut [&mut dyn App<ResponseSize>]) -> Option<Interface> {
433434
// Only take on one transaction at a time.
434435
let request_type = self.check_for_request();
435436

dispatch/tests/dispatch.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use apdu_dispatch::app::{App, Result as AppResult};
1+
use apdu_dispatch::app::{App, CommandView, Result as AppResult};
22
use apdu_dispatch::dispatch;
3-
use apdu_dispatch::Command;
43
use apdu_dispatch::{interchanges, response};
54
use hex_literal::hex;
65
use interchange::Channel;
@@ -48,11 +47,11 @@ impl iso7816::App for TestApp1 {
4847
}
4948

5049
// This app echos to Ins code 0x10
51-
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for TestApp1 {
50+
impl App<{ apdu_dispatch::response::SIZE }> for TestApp1 {
5251
fn select(
5352
&mut self,
5453
_interface: dispatch::Interface,
55-
_apdu: &Command,
54+
_apdu: CommandView<'_>,
5655
_reply: &mut response::Data,
5756
) -> AppResult {
5857
Ok(())
@@ -63,7 +62,7 @@ impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> fo
6362
fn call(
6463
&mut self,
6564
_: dispatch::Interface,
66-
apdu: &Command,
65+
apdu: CommandView<'_>,
6766
reply: &mut response::Data,
6867
) -> AppResult {
6968
println!("TestApp1::call");
@@ -123,11 +122,11 @@ impl iso7816::App for TestApp2 {
123122
}
124123

125124
// This app echos to Ins code 0x20
126-
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for TestApp2 {
125+
impl App<{ apdu_dispatch::response::SIZE }> for TestApp2 {
127126
fn select(
128127
&mut self,
129128
_interface: dispatch::Interface,
130-
_apdu: &Command,
129+
_apdu: CommandView<'_>,
131130
_reply: &mut response::Data,
132131
) -> AppResult {
133132
Ok(())
@@ -138,7 +137,7 @@ impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> fo
138137
fn call(
139138
&mut self,
140139
_: dispatch::Interface,
141-
apdu: &Command,
140+
apdu: CommandView<'_>,
142141
reply: &mut response::Data,
143142
) -> AppResult {
144143
println!("TestApp2::call");
@@ -175,11 +174,11 @@ impl iso7816::App for PanicApp {
175174
}
176175

177176
// This app echos to Ins code 0x20
178-
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for PanicApp {
177+
impl App<{ apdu_dispatch::response::SIZE }> for PanicApp {
179178
fn select(
180179
&mut self,
181180
_interface: dispatch::Interface,
182-
_apdu: &Command,
181+
_apdu: CommandView<'_>,
183182
_reply: &mut response::Data,
184183
) -> AppResult {
185184
panic!("Dont call the panic app");
@@ -192,7 +191,7 @@ impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> fo
192191
fn call(
193192
&mut self,
194193
_: dispatch::Interface,
195-
_apdu: &Command,
194+
_apdu: CommandView<'_>,
196195
_reply: &mut response::Data,
197196
) -> AppResult {
198197
panic!("Dont call the panic app");

fuzz/fuzz_targets/fuzz_target_1.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ impl iso7816::App for FuzzAppImpl {
5353
}
5454
}
5555

56-
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for FuzzAppImpl {
56+
impl App<{ apdu_dispatch::response::SIZE }> for FuzzAppImpl {
5757
fn select(
5858
&mut self,
5959
_interface: iso7816::Interface,
60-
_apdu: &apdu_dispatch::Command,
60+
_apdu: apdu_dispatch::app::CommandView<'_>,
6161
_reply: &mut apdu_dispatch::response::Data,
6262
) -> AppResult {
6363
Ok(())
@@ -68,7 +68,7 @@ impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> fo
6868
fn call(
6969
&mut self,
7070
_: Interface,
71-
_apdu: &apdu_dispatch::Command,
71+
_apdu: apdu_dispatch::app::CommandView<'_>,
7272
reply: &mut apdu_dispatch::response::Data,
7373
) -> AppResult {
7474
let (ref data, status) = &self.responses[self.count];
@@ -91,7 +91,7 @@ fuzz_target!(|input: Input| {
9191
.collect();
9292
let mut dyn_apps: Vec<_> = apps
9393
.iter_mut()
94-
.map(|s| (s as &mut dyn apdu_dispatch::App<7609, 7609>))
94+
.map(|s| (s as &mut dyn apdu_dispatch::App<7609>))
9595
.collect();
9696

9797
let contact = Channel::new();

0 commit comments

Comments
 (0)