mirror of
https://github.com/trussed-dev/flexiber.git
synced 2026-03-11 16:35:17 -07:00
269 lines
6.5 KiB
Rust
269 lines
6.5 KiB
Rust
//! Tests for custom derive support
|
|
|
|
#![cfg(feature = "derive")]
|
|
|
|
use flexiber as ber;
|
|
use flexiber::{Decodable, Encodable};
|
|
|
|
#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
|
|
#[tlv(number = "0xAA")]
|
|
struct S {
|
|
#[tlv(slice, number = "0x11")]
|
|
x: [u8; 2],
|
|
#[tlv(slice, number = "0x22")]
|
|
y: [u8; 3],
|
|
#[tlv(slice, number = "0x33")]
|
|
z: [u8; 4],
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
|
|
#[tlv(application, number = "0xAA")]
|
|
struct SApp {
|
|
#[tlv(slice, number = "0x11")]
|
|
x: [u8; 2],
|
|
#[tlv(slice, number = "0x22")]
|
|
y: [u8; 3],
|
|
#[tlv(slice, number = "0x33")]
|
|
z: [u8; 4],
|
|
}
|
|
|
|
#[test]
|
|
fn derived_reconstruct() {
|
|
let s = S {
|
|
x: [1, 2],
|
|
y: [3, 4, 5],
|
|
z: [6, 7, 8, 9],
|
|
};
|
|
let mut buf = [0u8; 1024];
|
|
|
|
let encoded = s.encode_to_slice(&mut buf).unwrap();
|
|
|
|
assert_eq!(
|
|
encoded,
|
|
&[0x1F, 0x81, 0x2A, 17, 0x11, 2, 1, 2, 0x1F, 0x22, 3, 3, 4, 5, 0x1F, 0x33, 4, 6, 7, 8, 9,],
|
|
);
|
|
|
|
let s2 = S::from_bytes(encoded).unwrap();
|
|
assert_eq!(s, s2);
|
|
}
|
|
|
|
#[test]
|
|
fn derived_reconstruct_application() {
|
|
let s = SApp {
|
|
x: [1, 2],
|
|
y: [3, 4, 5],
|
|
z: [6, 7, 8, 9],
|
|
};
|
|
let mut buf = [0u8; 1024];
|
|
|
|
let encoded = s.encode_to_slice(&mut buf).unwrap();
|
|
|
|
assert_eq!(
|
|
encoded,
|
|
&[0x5F, 0x81, 0x2A, 17, 0x11, 2, 1, 2, 0x1F, 0x22, 3, 3, 4, 5, 0x1F, 0x33, 4, 6, 7, 8, 9,],
|
|
);
|
|
|
|
let s2 = SApp::from_bytes(encoded).unwrap();
|
|
assert_eq!(s, s2);
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
|
|
#[tlv(constructed, number = "0x10")]
|
|
struct T {
|
|
#[tlv(number = "0x44", slice)]
|
|
x: [u8; 1234],
|
|
}
|
|
|
|
#[test]
|
|
fn pretty_big() {
|
|
let mut x = [0u8; 1234];
|
|
for (i, x) in x.iter_mut().enumerate() {
|
|
*x = i as _;
|
|
}
|
|
|
|
let t = T { x };
|
|
|
|
let mut buf = [0u8; 1024];
|
|
assert!(t.encode_to_slice(&mut buf).is_err());
|
|
|
|
let mut buf = [0u8; 1500];
|
|
let encoded = t.encode_to_slice(&mut buf).unwrap();
|
|
|
|
assert_eq!(
|
|
&encoded[..9],
|
|
[
|
|
// 1234 + 5
|
|
0x30,
|
|
0x82,
|
|
0x04,
|
|
0xD2 + 5,
|
|
// 1234
|
|
0x1F,
|
|
0x44,
|
|
0x82,
|
|
0x04,
|
|
0xD2
|
|
]
|
|
);
|
|
assert_eq!(&encoded[9..], x);
|
|
|
|
let t2 = T::from_bytes(encoded).unwrap();
|
|
assert_eq!(t, t2);
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
|
|
struct T2 {
|
|
#[tlv(private, primitive, number = "0x44", slice)]
|
|
x: [u8; 1234],
|
|
#[tlv(simple = "0x55", slice)]
|
|
a: [u8; 5],
|
|
}
|
|
|
|
#[test]
|
|
fn derive_untagged() {
|
|
let mut x = [0u8; 1234];
|
|
for (i, x) in x.iter_mut().enumerate() {
|
|
*x = i as _;
|
|
}
|
|
|
|
let t = T2 { x, a: [17u8; 5] };
|
|
|
|
let mut buf = [0u8; 1500];
|
|
let encoded = t.encode_to_slice(&mut buf).unwrap();
|
|
|
|
assert_eq!(
|
|
&encoded[..5],
|
|
[
|
|
// 1234
|
|
223, 0x44, 0x82, 0x04, 0xD2
|
|
]
|
|
);
|
|
assert_eq!(&encoded[5..(encoded.len() - 7)], x);
|
|
assert_eq!(
|
|
&encoded[(encoded.len() - 7)..],
|
|
[0x55, 5, 17, 17, 17, 17, 17]
|
|
);
|
|
|
|
let t2 = T2::from_bytes(encoded).unwrap();
|
|
assert_eq!(t, t2);
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub struct PinUsagePolicy {
|
|
piv_pin: bool,
|
|
global_pin: bool,
|
|
on_card_biometric_comparison: bool,
|
|
|
|
has_virtual_contact_interface: bool,
|
|
pairing_code_required_for_vci: Option<bool>,
|
|
|
|
cardholder_prefers_global_pin: Option<bool>,
|
|
}
|
|
|
|
impl Default for PinUsagePolicy {
|
|
fn default() -> Self {
|
|
Self {
|
|
piv_pin: true,
|
|
global_pin: false,
|
|
on_card_biometric_comparison: false,
|
|
has_virtual_contact_interface: false,
|
|
pairing_code_required_for_vci: None,
|
|
cardholder_prefers_global_pin: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Decodable<'_> for PinUsagePolicy {
|
|
fn decode(decoder: &mut ber::Decoder<'_>) -> ber::Result<Self> {
|
|
let raw: [u8; 2] = decoder.decode()?;
|
|
let capabilities = raw[0];
|
|
let has_global_pin = capabilities & (1 << 5) != 0;
|
|
let has_virtual_contact_interface = capabilities & (1 << 3) != 0;
|
|
Ok(Self {
|
|
piv_pin: capabilities & (1 << 6) != 0,
|
|
global_pin: has_global_pin,
|
|
on_card_biometric_comparison: capabilities & (1 << 4) != 0,
|
|
has_virtual_contact_interface,
|
|
pairing_code_required_for_vci: if has_virtual_contact_interface {
|
|
Some(capabilities & (1 << 2) != 0)
|
|
} else {
|
|
None
|
|
},
|
|
|
|
cardholder_prefers_global_pin: if has_global_pin {
|
|
Some(raw[1] == 0x20)
|
|
} else {
|
|
None
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Encodable for PinUsagePolicy {
|
|
fn encoded_length(&self) -> ber::Result<ber::Length> {
|
|
Ok(2u8.into())
|
|
}
|
|
|
|
fn encode(&self, encoder: &mut ber::Encoder<'_>) -> ber::Result<()> {
|
|
let mut first_byte = 0u8;
|
|
if self.piv_pin {
|
|
first_byte |= 1 << 6;
|
|
}
|
|
if self.global_pin {
|
|
first_byte |= 1 << 5;
|
|
}
|
|
if self.on_card_biometric_comparison {
|
|
first_byte |= 1 << 4;
|
|
}
|
|
if self.has_virtual_contact_interface {
|
|
first_byte |= 1 << 3;
|
|
}
|
|
|
|
if self.has_virtual_contact_interface && Some(true) == self.pairing_code_required_for_vci {
|
|
first_byte |= 1 << 2;
|
|
}
|
|
|
|
let mut second_byte = 0u8;
|
|
if self.global_pin {
|
|
if let Some(prefers_global) = self.cardholder_prefers_global_pin {
|
|
if prefers_global {
|
|
second_byte = 0x20;
|
|
} else {
|
|
second_byte = 0x10;
|
|
}
|
|
}
|
|
}
|
|
|
|
encoder.encode(&[first_byte, second_byte])
|
|
}
|
|
}
|
|
|
|
#[derive(Decodable, Encodable)]
|
|
#[tlv(application, constructed, number = "0x1E")] // = 0x7E
|
|
pub struct DiscoveryObject {
|
|
#[tlv(slice, application, number = "0xF")]
|
|
piv_card_application_aid: [u8; 11],
|
|
#[tlv(application, number = "0x2f")]
|
|
pin_usage_policy: PinUsagePolicy,
|
|
}
|
|
|
|
impl Default for DiscoveryObject {
|
|
fn default() -> Self {
|
|
Self {
|
|
piv_card_application_aid: hex_literal::hex!("A000000308 00001000 0100"),
|
|
pin_usage_policy: Default::default(), //[0x40, 0x00],
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn discovery() {
|
|
let disco = DiscoveryObject::default();
|
|
let mut buf = [0u8; 64];
|
|
let encoded = disco.encode_to_slice(&mut buf).unwrap();
|
|
assert_eq!(
|
|
encoded,
|
|
hex_literal::hex!("7e124f0ba0000003080000100001005f2f024000")
|
|
);
|
|
}
|