1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! This module implements a simple TLV-BER parser, parsing a byte array and returning nested
16 //! [`Object`]s that represent the contents. It does not define/implement standard ASN.1 types
17 //! (e.g. INTEGER, SEQUENCE, etc.) because they're not required by the ARA data structures.
18 //!
19 //! The reason this was written rather than using an existing crate is that the existing options
20 //! parse TLV-DER, and diagnose and report non-canonical encodings. The ARA rule set is TLV-BER
21 //! encoded, not TLV-DER, because canonicalization is not required.
22
23 use strum_macros::{Display, EnumIter};
24 use thiserror::Error;
25
26 /// Trait that defines a common interface for parsing things from bytes.
27 trait Parseable<'a>: 'a + Sized {
parse(input: &'a [u8]) -> Result<(Self, &'a [u8]), TlvParseError>28 fn parse(input: &'a [u8]) -> Result<(Self, &'a [u8]), TlvParseError>;
29 }
30
31 #[derive(Debug, Error, PartialEq)]
32 pub enum TlvParseError {
33 #[error("Parse buffer exhausted; needed {need} bytes, found {found}")]
34 BufferInsufficient { need: usize, found: usize },
35 #[error("Can't get class of empty tag value")]
36 EmptyTagValue,
37 #[error("Invalid multi-byte tag")]
38 InvalidMultiByteTag,
39 }
40
41 /// The parsed TLV data structure.
42 ///
43 /// The content is simple: a [`Tag`] object that specifies the extracted tag, and a [`Value`] object
44 /// with the contained value.
45 #[derive(Debug, Clone, PartialEq)]
46 pub struct Object<'a> {
47 tag: Tag,
48 value: Value<'a>,
49 }
50
51 impl<'a> Object<'a> {
52 #[cfg(test)]
new(tag: Tag, value: Value<'a>) -> Self53 pub fn new(tag: Tag, value: Value<'a>) -> Self {
54 Object { tag, value }
55 }
56
tag(&self) -> &Tag57 pub fn tag(&self) -> &Tag {
58 &self.tag
59 }
60
value(&self) -> &Value61 pub fn value(&self) -> &Value {
62 &self.value
63 }
64
get_content(self) -> Value<'a>65 pub fn get_content(self) -> Value<'a> {
66 self.value
67 }
68 }
69
70 impl<'a> Parseable<'a> for Object<'a> {
parse(input: &'a [u8]) -> Result<(Self, &'a [u8]), TlvParseError>71 fn parse(input: &'a [u8]) -> Result<(Self, &'a [u8]), TlvParseError> {
72 let (header, remainder) = Header::parse(input)?;
73
74 if remainder.len() < header.length.0 {
75 return Err(TlvParseError::BufferInsufficient {
76 need: header.length.0,
77 found: remainder.len(),
78 });
79 }
80
81 let (tag, value, remainder) = Value::parse(header, remainder)?;
82 Ok((Object { tag, value }, remainder))
83 }
84 }
85
86 /// Value represents the content of a TLV object, whether [`Value::Empty`], meaning the TLV value
87 /// was empty, [`Value::Constructed`], meaning the value consists of a set of zero or more
88 /// contained TLV objects, or [`Value::Primitive`], meaning the value does not contain other TLV
89 /// objects, but only some primitive content. Primitive content is provided only as a byte array.
90 #[derive(Display, Debug, Clone, PartialEq)]
91 pub enum Value<'a> {
92 Empty,
93 Primitive(&'a [u8]),
94 Constructed(Vec<Object<'a>>),
95 }
96
97 impl<'a> Value<'a> {
parse(header: Header, input: &'a [u8]) -> Result<(Tag, Value<'a>, &'a [u8]), TlvParseError>98 fn parse(header: Header, input: &'a [u8]) -> Result<(Tag, Value<'a>, &'a [u8]), TlvParseError> {
99 let value_buf = &input[..header.length.0];
100
101 let value = if header.length.0 == 0 {
102 Value::Empty
103 } else if header.tag.is_constructed()? {
104 parse_constructed_content(value_buf)?
105 } else {
106 Value::Primitive(value_buf)
107 };
108
109 Ok((header.tag, value, &input[header.length.0..]))
110 }
111 }
112
113 struct Header {
114 tag: Tag,
115 length: Asn1Length,
116 }
117
118 impl Parseable<'_> for Header {
parse(input: &[u8]) -> Result<(Self, &[u8]), TlvParseError>119 fn parse(input: &[u8]) -> Result<(Self, &[u8]), TlvParseError> {
120 let (tag, remainder) = Tag::parse(input)?;
121 let (length, remainder) = Asn1Length::parse(remainder)?;
122
123 Ok((Header { tag, length }, remainder))
124 }
125 }
126
127 struct Asn1Length(usize);
128
129 impl Parseable<'_> for Asn1Length {
parse(input: &[u8]) -> Result<(Self, &[u8]), TlvParseError>130 fn parse(input: &[u8]) -> Result<(Self, &[u8]), TlvParseError> {
131 if input.is_empty() {
132 return Err(TlvParseError::BufferInsufficient { need: 1, found: 0 });
133 }
134
135 if input[0] & 0x80 == 0x00 {
136 Ok((Asn1Length((input[0] & 0x7F) as usize), &input[1..]))
137 } else {
138 parse_multi_byte_length(input)
139 }
140 }
141 }
142
143 /// The set of supported tags. Additional tags can be added if needed, though unknown tags are
144 /// handled cleanly as [`Tag::Unknown`].
145 #[derive(Display, Debug, Clone, EnumIter, PartialEq)]
146 pub enum Tag {
147 AidRefDoSpecificApplet,
148 AidRefDoImplicit,
149 DeviceAppIdRefDo,
150 ApduArDo,
151 NfcArDo,
152 RefDo,
153 RefArDo,
154 ArDo,
155 PkgRefDo,
156 ResponseRefreshTagDo,
157 ResponseAllRefArDo,
158 Unknown(Vec<u8>),
159 }
160
161 impl Tag {
new(tag_val: &[u8]) -> Self162 pub fn new(tag_val: &[u8]) -> Self {
163 match tag_val {
164 [0x4F] => Self::AidRefDoSpecificApplet,
165 [0xC0] => Self::AidRefDoImplicit,
166 [0xC1] => Self::DeviceAppIdRefDo,
167 [0xCA] => Self::PkgRefDo,
168 [0xD0] => Self::ApduArDo,
169 [0xD1] => Self::NfcArDo,
170 [0xE1] => Self::RefDo,
171 [0xE2] => Self::RefArDo,
172 [0xE3] => Self::ArDo,
173 [0xDF, 0x20] => Self::ResponseRefreshTagDo,
174 [0xFF, 0x40] => Self::ResponseAllRefArDo,
175 tag_val => Self::Unknown(tag_val.to_vec()),
176 }
177 }
178
bytes(&self) -> &[u8]179 pub fn bytes(&self) -> &[u8] {
180 match self {
181 Tag::AidRefDoImplicit => &[0xC0],
182 Tag::AidRefDoSpecificApplet => &[0x4F],
183 Tag::ApduArDo => &[0xD0],
184 Tag::ArDo => &[0xE3],
185 Tag::DeviceAppIdRefDo => &[0xC1],
186 Tag::NfcArDo => &[0xD1],
187 Tag::PkgRefDo => &[0xCA],
188 Tag::RefArDo => &[0xE2],
189 Tag::RefDo => &[0xE1],
190 Tag::ResponseRefreshTagDo => &[0xDF, 0x20],
191 Tag::ResponseAllRefArDo => &[0xFF, 0x40],
192 Tag::Unknown(vec) => vec,
193 }
194 }
195
is_constructed(&self) -> Result<bool, TlvParseError>196 fn is_constructed(&self) -> Result<bool, TlvParseError> {
197 Ok(self.first_byte()? & 0x20 == 0x20)
198 }
199
first_byte(&self) -> Result<&u8, TlvParseError>200 fn first_byte(&self) -> Result<&u8, TlvParseError> {
201 self.bytes().first().ok_or(TlvParseError::EmptyTagValue)
202 }
203 }
204
205 impl Parseable<'_> for Tag {
parse(input: &[u8]) -> Result<(Self, &[u8]), TlvParseError>206 fn parse(input: &[u8]) -> Result<(Self, &[u8]), TlvParseError> {
207 let Some(first) = input.first() else {
208 return Err(TlvParseError::BufferInsufficient { need: 1, found: 0 });
209 };
210
211 let (tag, remainder) = {
212 // Single-byte tags use the five low order bits to encode the tag values 0-30. If those
213 // bits contain 31 (0x1F), it's a multi-byte tag.
214 if first & 0x1F != 0x1F {
215 (Tag::new(&input[..1]), &input[1..])
216 } else {
217 parse_multi_byte_tag(input)?
218 }
219 };
220
221 Ok((tag, remainder))
222 }
223 }
224
225 /// Parse the provided buffer, returning an [`Object`] representing the parsed data and a slice
226 /// that references the unused portion of the buffer (if any; callers should probably assume that
227 /// a non-empty unused buffer means the input data was malformed).
parse(input: &[u8]) -> Result<(Object, &[u8]), TlvParseError>228 pub fn parse(input: &[u8]) -> Result<(Object, &[u8]), TlvParseError> {
229 Object::parse(input)
230 }
231
parse_multi_byte_tag(input: &[u8]) -> Result<(Tag, &[u8]), TlvParseError>232 fn parse_multi_byte_tag(input: &[u8]) -> Result<(Tag, &[u8]), TlvParseError> {
233 assert!(!input.is_empty());
234
235 let Some(first_len_byte) = input.get(1) else {
236 return Err(TlvParseError::InvalidMultiByteTag);
237 };
238
239 if first_len_byte & 0x7F == 0 {
240 return Err(TlvParseError::InvalidMultiByteTag);
241 }
242
243 // A multi-byte tag consists of a header byte followed by a sequence of bytes with high-order
244 // bit 1, followed by a byte with high-order bit 0.
245 let tag_size = 1 + count_bytes_with_high_order_bit_set(&input[1..]) + 1;
246 if input.len() < tag_size {
247 return Err(TlvParseError::InvalidMultiByteTag);
248 }
249 Ok((Tag::new(&input[..tag_size]), &input[tag_size..]))
250 }
251
count_bytes_with_high_order_bit_set(input: &[u8]) -> usize252 fn count_bytes_with_high_order_bit_set(input: &[u8]) -> usize {
253 input.iter().take_while(|b| *b & 0x80 == 0x80).count()
254 }
255
parse_multi_byte_length(input: &[u8]) -> Result<(Asn1Length, &[u8]), TlvParseError>256 fn parse_multi_byte_length(input: &[u8]) -> Result<(Asn1Length, &[u8]), TlvParseError> {
257 let field_len = (input[0] & 0x7F) as usize;
258 if input.len() < field_len + 1 {
259 return Err(TlvParseError::BufferInsufficient { need: field_len + 1, found: input.len() });
260 }
261
262 let mut len: usize = 0;
263 for b in &input[1..=field_len] {
264 len = len * 256 + *b as usize;
265 }
266 Ok((Asn1Length(len), &input[1 + field_len..]))
267 }
268
parse_constructed_content(mut input: &[u8]) -> Result<Value, TlvParseError>269 fn parse_constructed_content(mut input: &[u8]) -> Result<Value, TlvParseError> {
270 let mut objects = Vec::new();
271 while !input.is_empty() {
272 let (object, remaining_buf) = Object::parse(input)?;
273 input = remaining_buf;
274 objects.push(object);
275 }
276 Ok(Value::Constructed(objects))
277 }
278
279 #[cfg(test)]
280 mod tests {
281 use super::*;
282 use googletest::prelude::*;
283 use googletest::test as gtest;
284
285 use strum::IntoEnumIterator;
286
287 #[gtest]
parse_empty_tag() -> Result<()>288 fn parse_empty_tag() -> Result<()> {
289 let data = [];
290 let result = Tag::parse(&data);
291 assert_that!(
292 result.unwrap_err(),
293 eq(&TlvParseError::BufferInsufficient { need: 1, found: 0 })
294 );
295
296 Ok(())
297 }
298
299 #[gtest]
unknown_tag() -> Result<()>300 fn unknown_tag() -> Result<()> {
301 let data = [
302 0x00, // Tag
303 0x00, // Length
304 ];
305
306 let (tag, _rest) = Tag::parse(&data)?;
307 assert_eq!(tag, Tag::Unknown(vec![0x00]));
308
309 let data = [
310 0x1F, 0x01, // Two-byte tag
311 0x00, // Length
312 ];
313
314 let (tag, _rest) = Tag::parse(&data)?;
315 assert_eq!(tag, Tag::Unknown(vec![0x1F, 0x01]));
316
317 let data = [
318 0x1F, 0x81, 0x01, // Three-byte tag
319 0x00, // Length
320 ];
321
322 let (tag, _rest) = Tag::parse(&data)?;
323 assert_eq!(tag, Tag::Unknown(vec![0x1F, 0x81, 0x01]));
324
325 Ok(())
326 }
327
328 #[gtest]
parse_empty_len() -> Result<()>329 fn parse_empty_len() -> Result<()> {
330 let data = [];
331 let result = Asn1Length::parse(&data);
332 assert!(result.is_err());
333 Ok(())
334 }
335
336 #[test]
parse_short_buf() -> Result<()>337 fn parse_short_buf() -> Result<()> {
338 let data = [
339 0x00, // Tag
340 0x02, // Length - need two bytes
341 ];
342
343 let result = parse(&data);
344 assert!(result.is_err());
345 Ok(())
346 }
347
348 #[gtest]
parse_rule_set_with_nop_rule() -> Result<()>349 fn parse_rule_set_with_nop_rule() -> Result<()> {
350 let data = [
351 0xFF, 0x40, // Response-ALL-REF-AR-DO
352 0x0D, // 13 bytes long
353 0xE2, // REF-AR-DO tag
354 0x0B, // 11 bytes long (6 REF-DO, 5 AR-DO)
355 0xE1, // REF-DO tag
356 0x04, // 4 bytes long
357 0x4F, // AID-REF-DO tag
358 0x00, // 0 bytes (empty AID)
359 0xC1, // DeviceAppId-REF-DO tag
360 0x00, // 0 bytes (empty device ID)
361 0xE3, // AR-DO tag
362 0x03, // 3 bytes long
363 0xD0, // APDU-AR-DO tag
364 0x01, // 1 byte long
365 0x01, // 0x01 means ALWAYS allow.
366 ];
367
368 let (obj, rest) = parse(&data)?;
369 assert!(rest.is_empty());
370 assert_eq!(
371 obj,
372 Object::new(
373 Tag::ResponseAllRefArDo,
374 Value::Constructed(vec![Object::new(
375 Tag::RefArDo,
376 Value::Constructed(vec![
377 Object::new(
378 Tag::RefDo,
379 Value::Constructed(vec![
380 Object::new(Tag::AidRefDoSpecificApplet, Value::Empty),
381 Object::new(Tag::DeviceAppIdRefDo, Value::Empty)
382 ])
383 ),
384 Object::new(
385 Tag::ArDo,
386 Value::Constructed(vec![Object::new(
387 Tag::ApduArDo,
388 Value::Primitive(&[0x01])
389 )])
390 )
391 ])
392 )])
393 )
394 );
395
396 Ok(())
397 }
398
399 #[gtest]
parse_invalid_multi_byte_tag() -> Result<()>400 fn parse_invalid_multi_byte_tag() -> Result<()> {
401 // A multi-byte tag must be more than one byte.
402 assert_eq!(Tag::parse(&[0x1F]).unwrap_err(), TlvParseError::InvalidMultiByteTag);
403 // The last byte of a multi-byte tag must have the high order bit clear
404 assert_eq!(Tag::parse(&[0x1F, 0x81]).unwrap_err(), TlvParseError::InvalidMultiByteTag);
405 // bit 7-0 may not be zero
406 assert_eq!(Tag::parse(&[0x1F, 0x00]).unwrap_err(), TlvParseError::InvalidMultiByteTag);
407 // bit 7-0 may not be zero
408 assert_eq!(Tag::parse(&[0x1F, 0x80]).unwrap_err(), TlvParseError::InvalidMultiByteTag);
409 Ok(())
410 }
411
412 #[gtest]
test_tag_mappings() -> Result<()>413 fn test_tag_mappings() -> Result<()> {
414 for tag in Tag::iter() {
415 assert_eq!(Tag::new(tag.bytes()), tag);
416 if matches!(tag, Tag::Unknown(_)) {
417 continue;
418 }
419 expect_that!(tag.is_constructed()?, eq(tag.first_byte()? & 0x20 == 0x20), "{tag}");
420 }
421 Ok(())
422 }
423
424 #[gtest]
test_incomplete_multi_byte_len() -> Result<()>425 fn test_incomplete_multi_byte_len() -> Result<()> {
426 let data = [
427 0x00, 0x82, // Length; should be followed by two bytes.
428 ];
429
430 let result = Header::parse(&data);
431 assert!(result.is_err());
432 Ok(())
433 }
434
435 #[gtest]
test_multi_byte_len() -> Result<()>436 fn test_multi_byte_len() -> Result<()> {
437 let data = [
438 0x82, // Length field, two-byte value
439 0x01, // Byte 1: 1 * 256
440 0x01, // Byte 2: 1
441 0xFF, // Extra byte; shouldn't be used.
442 ];
443
444 let (val, remaining_buf) = Asn1Length::parse(&data)?;
445 assert_eq!(val.0, 257);
446 assert_eq!(remaining_buf, [0xFF]);
447
448 Ok(())
449 }
450
451 #[gtest]
test_error_in_constructed_object() -> Result<()>452 fn test_error_in_constructed_object() -> Result<()> {
453 let data = [
454 0xE1, // RefDo tag
455 0x02, // Length
456 0x4F, // AidRefDo tag,
457 0x82, // Invalid length
458 ];
459
460 let result = parse(&data);
461 assert!(result.is_err());
462 Ok(())
463 }
464 }
465