diff --git a/src/header.rs b/src/header.rs index 7291cb7..3975802 100644 --- a/src/header.rs +++ b/src/header.rs @@ -352,19 +352,33 @@ impl ToDer for (Class, bool, Tag) { let b0 = (*class as u8) << 6; let b0 = b0 | if *constructed { 0b10_0000 } else { 0 }; if tag.0 > 30 { + let mut val = tag.0; + + const BUF_SZ: usize = 8; + let mut buffer = [0u8; BUF_SZ]; + let mut current_index = BUF_SZ - 1; + + // first byte: class+constructed+0x1f let b0 = b0 | 0b1_1111; let mut sz = writer.write(&[b0])?; - let mut val = tag.0; - loop { - if val <= 127 { - sz += writer.write(&[val as u8])?; - return Ok(sz); - } else { - let b = (val & 0b0111_1111) as u8 | 0b1000_0000; - sz += writer.write(&[b])?; - val >>= 7; + + // now write bytes from right (last) to left + + // last encoded byte + buffer[current_index] = (val & 0x7f) as u8; + val >>= 7; + + while val > 0 { + current_index -= 1; + if current_index == 0 { + return Err(SerializeError::InvalidLength); } + buffer[current_index] = (val & 0x7f) as u8 | 0x80; + val >>= 7; } + + sz += writer.write(&buffer[current_index..])?; + Ok(sz) } else { let b0 = b0 | (tag.0 as u8); let sz = writer.write(&[b0])?; diff --git a/tests/issue-43-encoding-large-tags.rs b/tests/issue-43-encoding-large-tags.rs new file mode 100644 index 0000000..4fb6705 --- /dev/null +++ b/tests/issue-43-encoding-large-tags.rs @@ -0,0 +1,14 @@ +use asn1_rs::{Any, FromDer, Integer, Tag, ToDer}; + +#[test] +fn encode_large_tag() { + const EXPECTED_TAG: u32 = 0x41424344; + let data = Integer::from(1).to_der_vec().unwrap(); + let any = &Any::from_tag_and_data(Tag::from(EXPECTED_TAG), &data); + let tmp = any.to_der_vec().unwrap(); + + let expect = Tag::from(EXPECTED_TAG); + let actual = Any::from_der(&tmp).unwrap().1.tag(); + + assert_eq!(expect, actual, "expected tag {expect}, found tag {actual}"); +} diff --git a/tests/to_der.rs b/tests/to_der.rs index 05c523f..61dcc9a 100644 --- a/tests/to_der.rs +++ b/tests/to_der.rs @@ -68,7 +68,7 @@ fn to_der_tag() { let v = (Class::Universal, false, Tag(0x1a1a)) .to_der_vec() .expect("serialization failed"); - assert_eq!(&v, &[0b1_1111, 0x9a, 0x34]); + assert_eq!(&v, &[0b1_1111, 0xb4, 0x1a]); } #[test]