• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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