1use crate::command::{build, push, push_lv, BuildError, Capdu};
10
11#[allow(clippy::module_name_repetitions)] pub fn delete_object(aid: &[u8], cascade: bool) -> Result<Capdu, BuildError> {
22 let mut data = Capdu::new();
23 push(&mut data, &[0x4F])?;
24 push_lv(&mut data, aid)?;
25 let p2 = if cascade { 0x80 } else { 0x00 };
26 build(0x84, 0xE4, 0x00, p2, &data, true)
27}
28
29#[allow(clippy::module_name_repetitions)] pub fn delete_key(kid: Option<u8>, kvn: Option<u8>) -> Result<Capdu, BuildError> {
42 if kid.is_none() && kvn.is_none() {
43 return Err(BuildError::EmptyKeyScope);
44 }
45 let mut data = Capdu::new();
46 if let Some(kid) = kid {
47 push(&mut data, &[0xD0, 0x01, kid])?;
48 }
49 if let Some(kvn) = kvn {
50 push(&mut data, &[0xD2, 0x01, kvn])?;
51 }
52 build(0x84, 0xE4, 0x00, 0x00, &data, true)
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use proptest::prelude::*;
59 use scll_test_util::HexSlice;
60
61 #[test]
62 fn delete_object_only_uses_p2_00() {
63 let aid = [0xA0, 0x00, 0x00, 0x01, 0x51];
64 let apdu = delete_object(&aid, false).unwrap();
65 assert_eq!(
66 HexSlice(&apdu),
67 HexSlice([
68 0x84, 0xE4, 0x00, 0x00, 0x07, 0x4F, 0x05, 0xA0, 0x00, 0x00, 0x01, 0x51, 0x00
69 ])
70 );
71 }
72
73 #[test]
74 fn delete_object_cascade_uses_p2_80() {
75 let aid = [0xA0, 0x00, 0x00, 0x01, 0x51];
76 let apdu = delete_object(&aid, true).unwrap();
77 assert_eq!(apdu[3], 0x80); }
79
80 #[test]
81 fn delete_single_key_carries_both_tags_d0_then_d2() {
82 let apdu = delete_key(Some(0x01), Some(0x30)).unwrap();
83 assert_eq!(
84 HexSlice(&apdu),
85 HexSlice([0x84, 0xE4, 0x00, 0x00, 0x06, 0xD0, 0x01, 0x01, 0xD2, 0x01, 0x30, 0x00])
86 );
87 }
88
89 #[test]
90 fn delete_all_kvns_for_a_kid_omits_d2() {
91 let apdu = delete_key(Some(0x02), None).unwrap();
92 assert_eq!(
93 HexSlice(&apdu),
94 HexSlice([0x84, 0xE4, 0x00, 0x00, 0x03, 0xD0, 0x01, 0x02, 0x00])
95 );
96 }
97
98 #[test]
99 fn delete_all_kids_for_a_kvn_omits_d0() {
100 let apdu = delete_key(None, Some(0x30)).unwrap();
101 assert_eq!(
102 HexSlice(&apdu),
103 HexSlice([0x84, 0xE4, 0x00, 0x00, 0x03, 0xD2, 0x01, 0x30, 0x00])
104 );
105 }
106
107 #[test]
108 fn delete_key_needs_at_least_one_scope() {
109 assert_eq!(delete_key(None, None), Err(BuildError::EmptyKeyScope));
110 }
111
112 #[test]
113 fn oversized_object_aid_overflows() {
114 let big = [0x00u8; 255];
115 assert_eq!(delete_object(&big, false), Err(BuildError::Overflow));
116 }
117
118 proptest! {
119 #[test]
121 fn key_scope_combinations(
122 kid in proptest::option::of(any::<u8>()),
123 kvn in proptest::option::of(any::<u8>()),
124 ) {
125 if kid.is_none() && kvn.is_none() {
126 prop_assert_eq!(delete_key(kid, kvn), Err(BuildError::EmptyKeyScope));
127 } else {
128 let apdu = delete_key(kid, kvn).unwrap();
129 prop_assert_eq!(&apdu[0..4], &[0x84, 0xE4, 0x00, 0x00]);
130 let body = &apdu[5..apdu.len() - 1]; if let Some(k) = kid {
132 prop_assert_eq!(&body[0..3], &[0xD0, 0x01, k]);
133 }
134 if let Some(v) = kvn {
135 prop_assert_eq!(&body[body.len() - 3..], &[0xD2, 0x01, v]);
136 }
137 }
138 }
139 }
140}