mirror of
https://github.com/trussed-dev/apdu-dispatch.git
synced 2026-06-20 04:16:15 -07:00
Fix panic on response larger than interchanges::SIZE or response::SIZE
This commit is contained in:
committed by
Nicolas Stalder
parent
e30785029e
commit
d1b8498ba3
+14
-6
@@ -22,6 +22,14 @@ use iso7816::{
|
||||
command::FromSliceError,
|
||||
};
|
||||
|
||||
/// Maximum length of a data field of a response that can fit in an interchange message after
|
||||
/// concatenation of SW1SW2
|
||||
const MAX_INTERCHANGE_DATA: usize = if interchanges::SIZE < ResponseSize {
|
||||
interchanges::SIZE
|
||||
} else {
|
||||
ResponseSize
|
||||
} - 2;
|
||||
|
||||
pub use iso7816::Interface;
|
||||
|
||||
pub enum RequestType {
|
||||
@@ -270,7 +278,7 @@ impl ApduDispatch
|
||||
// If the reader is using chaining, we will simply
|
||||
// reply 61XX, and put the response in a buffer.
|
||||
// It is up to the reader to then send GetResponse
|
||||
// requests, to which we will return up to 256 bytes at a time.
|
||||
// requests, to which we will return up to `Le` bytes at a time.
|
||||
let (new_state, response) = match &mut self.buffer.raw {
|
||||
RawApduBuffer::Request(_) | RawApduBuffer::None => {
|
||||
info!("Unexpected GetResponse request.");
|
||||
@@ -281,10 +289,10 @@ impl ApduDispatch
|
||||
}
|
||||
RawApduBuffer::Response(res) => {
|
||||
|
||||
if self.was_request_chained || res.len() > interchanges::SIZE {
|
||||
if self.was_request_chained || res.len() > MAX_INTERCHANGE_DATA {
|
||||
|
||||
// Do not send more than the expected bytes
|
||||
let boundary = core::cmp::min(self.response_len_expected, res.len());
|
||||
let boundary = self.response_len_expected.min(res.len()).min(MAX_INTERCHANGE_DATA);
|
||||
|
||||
let to_send = &res[..boundary];
|
||||
let remaining = &res[boundary..];
|
||||
@@ -298,7 +306,7 @@ impl ApduDispatch
|
||||
// Last chunk has success code
|
||||
0x9000
|
||||
};
|
||||
message.extend_from_slice(&return_code.to_be_bytes()).ok();
|
||||
message.extend_from_slice(&return_code.to_be_bytes()).expect("Failed add to status bytes");
|
||||
if return_code == 0x9000 {
|
||||
(
|
||||
RawApduBuffer::None,
|
||||
@@ -314,8 +322,8 @@ impl ApduDispatch
|
||||
|
||||
} else {
|
||||
// Add success code
|
||||
res.extend_from_slice(&[0x90,00]).ok();
|
||||
(RawApduBuffer::None, interchanges::Data::from_slice(res.as_slice()).unwrap())
|
||||
res.extend_from_slice(&[0x90,00]).expect("Failed to add the status bytes");
|
||||
(RawApduBuffer::None, interchanges::Data::from_slice(&res.as_slice()).unwrap())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,6 +86,24 @@ impl App< {apdu_dispatch::command::SIZE}, {apdu_dispatch::response::SIZE},> for
|
||||
reply.extend_from_slice(&addr.to_be_bytes()).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Testing a response larger than the interchange's size
|
||||
0x21 => {
|
||||
reply.extend_from_slice(&[10; interchanges::SIZE+1]).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
0x22 => {
|
||||
reply.extend_from_slice(&[10; interchanges::SIZE-2]).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
0x23 => {
|
||||
reply.extend_from_slice(&[10; interchanges::SIZE-1]).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
0x24 => {
|
||||
reply.extend_from_slice(&[10; interchanges::SIZE]).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
_ =>
|
||||
Err(Status::InstructionNotSupportedOrInvalid)
|
||||
}
|
||||
@@ -1029,6 +1047,51 @@ fn send_select_preceded_with_zero_chained_data(){
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn response_larger_than_interchange(){
|
||||
// Sending a select after chaining 0 bytes should result in successful select operation
|
||||
let mut response1 = vec![0x0A; interchanges::SIZE-2];
|
||||
response1.extend_from_slice(&hex!("6103"));
|
||||
let mut response2 = vec![0x0A; interchanges::SIZE-2];
|
||||
response2.extend_from_slice(&hex!("9000"));
|
||||
let mut response3 = vec![0x0A; interchanges::SIZE-2];
|
||||
response3.extend_from_slice(&hex!("6101"));
|
||||
let mut response4 = vec![0x0A; interchanges::SIZE-2];
|
||||
response4.extend_from_slice(&hex!("6102"));
|
||||
run_apdus(
|
||||
&[
|
||||
// Select 1
|
||||
&hex!("00A40400 05 0A01000001"),
|
||||
&hex!("9000"),
|
||||
|
||||
&hex!("00210000 00ffff"),
|
||||
&response1,
|
||||
|
||||
// Get Response
|
||||
&hex!("00C00000 00"),
|
||||
&hex!("0A0A0A 9000"),
|
||||
|
||||
&hex!("00220000 00ffff"),
|
||||
&response2,
|
||||
|
||||
&hex!("00230000 00ffff"),
|
||||
&response3,
|
||||
|
||||
// Get Response
|
||||
&hex!("00C00000 00"),
|
||||
&hex!("0A 9000"),
|
||||
|
||||
&hex!("00240000 00ffff"),
|
||||
&response4,
|
||||
|
||||
// Get Response
|
||||
&hex!("00C00000 00"),
|
||||
&hex!("0A0A 9000"),
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user