Skip to main content

rustbac_core/services/
i_am.rs

1use crate::apdu::UnconfirmedRequestHeader;
2use crate::encoding::{
3    primitives::{
4        decode_app_enumerated, decode_app_unsigned, encode_app_enumerated, encode_app_unsigned,
5    },
6    reader::Reader,
7    tag::{AppTag, Tag},
8    writer::Writer,
9};
10use crate::types::ObjectId;
11use crate::{DecodeError, EncodeError};
12
13pub const SERVICE_I_AM: u8 = 0x00;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct IAmRequest {
17    pub device_id: ObjectId,
18    pub max_apdu: u32,
19    pub segmentation: u32,
20    pub vendor_id: u32,
21}
22
23impl IAmRequest {
24    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
25        UnconfirmedRequestHeader {
26            service_choice: SERVICE_I_AM,
27        }
28        .encode(w)?;
29
30        Tag::Application {
31            tag: AppTag::ObjectId,
32            len: 4,
33        }
34        .encode(w)?;
35        w.write_all(&self.device_id.raw().to_be_bytes())?;
36        encode_app_unsigned(w, self.max_apdu)?;
37        encode_app_enumerated(w, self.segmentation)?;
38        encode_app_unsigned(w, self.vendor_id)?;
39        Ok(())
40    }
41
42    pub fn decode_after_header(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
43        let device_id = match Tag::decode(r)? {
44            Tag::Application {
45                tag: AppTag::ObjectId,
46                len: 4,
47            } => {
48                let b = r.read_exact(4)?;
49                ObjectId::from_raw(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
50            }
51            _ => return Err(DecodeError::InvalidTag),
52        };
53        let max_apdu = decode_app_unsigned(r)?;
54        let segmentation = decode_app_enumerated(r)?;
55        let vendor_id = decode_app_unsigned(r)?;
56
57        Ok(Self {
58            device_id,
59            max_apdu,
60            segmentation,
61            vendor_id,
62        })
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::IAmRequest;
69    use crate::apdu::UnconfirmedRequestHeader;
70    use crate::encoding::{reader::Reader, tag::AppTag, tag::Tag, writer::Writer};
71    use crate::types::{ObjectId, ObjectType};
72
73    #[test]
74    fn i_am_segmentation_is_enumerated() {
75        let req = IAmRequest {
76            device_id: ObjectId::new(ObjectType::Device, 1234),
77            max_apdu: 1476,
78            segmentation: 3,
79            vendor_id: 260,
80        };
81        let mut buf = [0u8; 64];
82        let mut w = Writer::new(&mut buf);
83        req.encode(&mut w).unwrap();
84
85        let mut r = Reader::new(w.as_written());
86        let _hdr = UnconfirmedRequestHeader::decode(&mut r).unwrap();
87        let _obj = Tag::decode(&mut r).unwrap();
88        let _obj_data = r.read_exact(4).unwrap();
89        let _max = Tag::decode(&mut r).unwrap();
90        let _max_data = r.read_exact(2).unwrap();
91        let seg_tag = Tag::decode(&mut r).unwrap();
92        assert_eq!(
93            seg_tag,
94            Tag::Application {
95                tag: AppTag::Enumerated,
96                len: 1
97            }
98        );
99    }
100}