picky-asn1-der-0.4.0/.cargo_vcs_info.json0000644000000001540000000000100135640ustar { "git": { "sha1": "0603db3a2dbf29b9dac53fa321e955f6da206204" }, "path_in_vcs": "picky-asn1-der" }picky-asn1-der-0.4.0/CHANGELOG.md000064400000000000000000000026630072674642500142240ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased ## [0.4.0] 2022-11-07 ### Added - Derive additional traits for some types ([#171](https://github.com/Devolutions/picky-rs/pull/171)) ## [0.3.1] 2022-05-19 ### Changed - Make `ApplicationTag`’s inner value public - Update dependencies ## [0.3.0] 2022-02-02 ### Added - Support for `GeneralString` - `ApplicationTag` to encode ASN.1 application tags ### Changed - Bump minimal rustc version to 1.56 ## [0.2.5] 2021-05-27 ### Added - Support for `BMP_STRING` type ## [0.2.4] 2020-08-31 ### Changed - Update dependencies ## [0.2.3] 2020-07-07 ### Changed - Dependencies clean up ## [0.2.2] 2020-01-14 ### Fixed - Fix `Asn1RawDer` behind Application/Context tags issue [#14](https://github.com/Devolutions/picky-rs/issues/14). ## [0.2.1] 2020-01-10 ### Added - `Asn1RawDer` wrapper for user-provided raw DER. ## [0.2.0] 2019-12-23 ### Added - Add `from_reader_with_max_len` deserialization function to limit how many bytes can be read at most. ### Changed - `from_reader` function has a default limit of 10240 bytes before returning a truncated data error. Uses `from_reader_with_max_len` to change the limit. ### Fixed - Fix various crash found by fuzzing. picky-asn1-der-0.4.0/Cargo.toml0000644000000032150000000000100115630ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.60" name = "picky-asn1-der" version = "0.4.0" authors = [ "KizzyCode Software Labs./Keziah Biermann ", "Benoît CORTIER ", "Alexandr Yusuk ", ] include = [ "src/**/*", "README.md", "CHANGELOG.md", ] description = "An ASN.1-DER subset for serde" readme = "README.md" keywords = [ "serde", "asn1", "asn1-der", "serialize", "deserialize", ] categories = ["encoding"] license = "MIT OR Apache-2.0" repository = "https://github.com/Devolutions/picky-rs" [dependencies.lazy_static] version = "1.4.0" optional = true [dependencies.picky-asn1] version = "0.7.0" [dependencies.serde] version = "1.0.136" features = ["derive"] default-features = false [dependencies.serde_bytes] version = "0.11.5" [dev-dependencies.base64] version = "0.13.0" [dev-dependencies.num-bigint-dig] version = "0.8.1" [dev-dependencies.oid] version = "0.2.1" features = ["serde_support"] default-features = false [dev-dependencies.pretty_assertions] version = "1.2.1" [dev-dependencies.serde_bytes] version = "0.11.5" [features] debug_log = ["lazy_static"] picky-asn1-der-0.4.0/Cargo.toml.orig000064400000000000000000000020410072674642500152700ustar 00000000000000[package] name = "picky-asn1-der" version = "0.4.0" edition = "2021" rust-version = "1.60" authors = [ "KizzyCode Software Labs./Keziah Biermann ", "Benoît CORTIER ", "Alexandr Yusuk ", ] keywords = ["serde", "asn1", "asn1-der", "serialize", "deserialize"] categories = ["encoding"] description = "An ASN.1-DER subset for serde" license = "MIT OR Apache-2.0" repository = "https://github.com/Devolutions/picky-rs" readme = "README.md" include = ["src/**/*", "README.md", "CHANGELOG.md"] [dependencies] picky-asn1 = { version = "0.7.0", path = "../picky-asn1" } serde = { version = "1.0.136", default-features = false, features = ["derive"] } serde_bytes = "0.11.5" lazy_static = { version = "1.4.0", optional = true } [dev-dependencies] base64 = "0.13.0" pretty_assertions = "1.2.1" serde_bytes = "0.11.5" num-bigint-dig = "0.8.1" oid = { version = "0.2.1", default-features = false, features = ["serde_support"] } [features] debug_log = ["lazy_static"] picky-asn1-der-0.4.0/README.md000064400000000000000000000024600072674642500136650ustar 00000000000000[![Crates.io](https://img.shields.io/crates/v/picky-asn1-der.svg)](https://crates.io/crates/picky-asn1-der) [![docs.rs](https://docs.rs/picky-asn1-der/badge.svg)](https://docs.rs/picky-asn1-der) ![Crates.io](https://img.shields.io/crates/l/picky-asn1-der) Compatible with rustc 1.60. Minimal rustc version bumps happen [only with minor number bumps in this project](https://github.com/Devolutions/picky-rs/issues/89#issuecomment-868303478). # picky-asn1-der Portions of project [serde_asn1_der](https://github.com/KizzyCode/serde_asn1_der) are held by Keziah Biermann, 2019 as part of this project. This crate implements an ASN.1-DER subset for serde. The following types have built-in support: - `bool`: The ASN.1-BOOLEAN-type - `u8`, `u16`, `u32`, `u64`, `u128`, `usize`: The ASN.1-INTEGER-type - `()`: The ASN.1-NULL-type - `&[u8]`, `Vec`: The ASN.1-OctetString-type - `&str`, `String`: The ASN.1-UTF8String-type More advanced types are supported through wrappers: - Integer (as big integer) - Bit String - Object Identifier - Utf8 String - Numeric String - Printable String - IA5 String - Generalized Time - UTC Time - Application Tags from 0 to 15 - Context Tags from 0 to 15 Everything sequence-like combined out of these types is also supported out of the box. Check out doc.rs for tested code examples. picky-asn1-der-0.4.0/src/application_tag.rs000064400000000000000000000107040072674642500167010ustar 00000000000000use crate::misc::Length; use crate::Asn1RawDer; use picky_asn1::tag::{Tag, TagPeeker}; use serde::de::{Error, SeqAccess}; use serde::{de, ser}; use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; #[derive(Debug, PartialEq, Eq)] pub struct ApplicationTag(pub V); impl ApplicationTag { pub fn from(value: V) -> Self { Self(value) } } impl Clone for ApplicationTag { fn clone(&self) -> Self { Self(self.0.clone()) } } impl<'de, V: de::Deserialize<'de> + Debug + PartialEq, const T: u8> de::Deserialize<'de> for ApplicationTag { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { struct Visitor(PhantomData); impl<'de, E: de::Deserialize<'de> + Debug + PartialEq, const T: u8> de::Visitor<'de> for Visitor { type Value = E; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(&format!("A valid DER-encoded ApplicationTag{:02x}", T)) } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { #[derive(Debug, serde::Deserialize)] struct ApplicationTagInner { value: V, } let tag_peeker: TagPeeker = seq .next_element() .map_err(|e| A::Error::custom(format!("Cannot deserialize application tag: {:?}", e)))? .ok_or_else(|| A::Error::missing_field("ApplicationTag"))?; let tag = tag_peeker.next_tag; if !tag.is_application() { return Err(A::Error::custom(format!( "Expected Application class tag but got: {:?}", tag.class() ))); } if tag.number() != T { return Err(A::Error::custom(format!( "Expected Application number tag {} but got: {}", T, tag.number() ))); } let rest: ApplicationTagInner = seq .next_element() .map_err(|e| A::Error::custom(format!("Cannot deserialize application tag inner value: {:?}", e)))? .ok_or_else(|| A::Error::missing_field("ApplicationInnerValue"))?; Ok(rest.value) } } let inner = deserializer .deserialize_enum("ApplicationTag", &["ApplicationTag"], Visitor::(PhantomData)) .map_err(D::Error::custom)?; Ok(Self(inner)) } } impl ser::Serialize for ApplicationTag { fn serialize(&self, serializer: S) -> Result<::Ok, S::Error> where S: ser::Serializer, { use serde::ser::Error; let mut buff = Vec::new(); { let mut s = crate::Serializer::new_to_byte_buf(&mut buff); self.0 .serialize(&mut s) .map_err(|e| S::Error::custom(format!("Cannot serialize Application tag inner value: {:?}", e)))?; } let mut res = vec![Tag::application_constructed(T).inner()]; Length::serialize(buff.len(), &mut res) .map_err(|e| S::Error::custom(format!("Cannot serialize Length: {:?}", e)))?; res.extend_from_slice(&buff); Asn1RawDer(res).serialize(serializer) } } #[cfg(test)] mod tests { use crate::application_tag::ApplicationTag; use picky_asn1::restricted_string::Utf8String; use picky_asn1::wrapper::Utf8StringAsn1; #[test] fn test_application_tag() { let expected_raw = vec![106, 13, 12, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109]; let expected: ApplicationTag = ApplicationTag::from(Utf8StringAsn1::from( Utf8String::from_string("example.com".to_owned()).unwrap(), )); let app_10: ApplicationTag = crate::from_bytes(&expected_raw).unwrap(); let app_10_raw = crate::to_vec(&app_10).unwrap(); assert_eq!(expected, app_10); assert_eq!(expected_raw, app_10_raw); } } picky-asn1-der-0.4.0/src/de/boolean.rs000064400000000000000000000013310072674642500155460ustar 00000000000000use crate::{Asn1DerError, Result}; /// A deserializer for booleans pub struct Boolean; impl Boolean { /// The deserialized boolean for `data` pub fn deserialize(data: &[u8]) -> Result { // Check lengths if data.is_empty() { return Err(Asn1DerError::TruncatedData); } if data.len() > 1 { return Err(Asn1DerError::InvalidData); } // Parse the boolean Ok(match data[0] { 0x00 => { debug_log!("false!"); false } 0xff => { debug_log!("true!"); true } _ => return Err(Asn1DerError::InvalidData), }) } } picky-asn1-der-0.4.0/src/de/integer.rs000064400000000000000000000030460072674642500155710ustar 00000000000000use crate::{Asn1DerError, Result}; /// A trait that allows you to convert all unsigned integers from a `u128` (if possible) pub trait UInt: Sized + Copy { /// Converts `num` into `Self` fn from_u128(num: u128) -> Result; } macro_rules! impl_uint { ($type:ident) => { impl UInt for $type { fn from_u128(num: u128) -> Result { const MAX: u128 = $type::max_value() as u128; match num { _ if num > MAX => Err(Asn1DerError::UnsupportedValue), _ => Ok(num as Self) } } } }; ($($type:ident),+) => ($( impl_uint!($type); )+) } impl_uint!(usize, u128, u64, u32, u16, u8); /// A deserializer for unsigned integers pub struct UnsignedInteger; impl UnsignedInteger { /// The deserialized integer for `data` pub fn deserialize(data: &[u8]) -> Result { // Check that we have some data if data.is_empty() { return Err(Asn1DerError::TruncatedData); } // Check first byte (number is signed, has leading zero, ...) let data = match data[0] { 128..=255 => return Err(Asn1DerError::UnsupportedValue), 0 if data.len() > 1 && data[1] < 128 => return Err(Asn1DerError::InvalidData), 0 => &data[1..], _ => data, }; // Check the data length if data.len() > 16 { return Err(Asn1DerError::UnsupportedValue); } // Deserialize data let mut num = [0; 16]; num[16 - data.len()..].copy_from_slice(data); T::from_u128(u128::from_be_bytes(num)) } } picky-asn1-der-0.4.0/src/de/mod.rs000064400000000000000000000701540072674642500147170ustar 00000000000000mod boolean; mod integer; mod null; mod sequence; mod utf8_string; use crate::de::boolean::Boolean; use crate::de::integer::UnsignedInteger; use crate::de::null::Null; use crate::de::sequence::Sequence; use crate::de::utf8_string::Utf8String; use crate::misc::{Length, PeekableReader, ReadExt}; use crate::{Asn1DerError, Asn1RawDer, Result}; use picky_asn1::tag::Tag; use picky_asn1::wrapper::*; use picky_asn1::Asn1Type; use serde::de::Visitor; use serde::Deserialize; use std::io::{Cursor, Read}; const DEFAULT_MAX_LEN: usize = 10240; /// Deserializes `T` from `bytes` pub fn from_bytes<'a, T: Deserialize<'a>>(bytes: &'a [u8]) -> Result { debug_log!("deserialization using `from_bytes`"); let mut deserializer = Deserializer::new_from_bytes(bytes); T::deserialize(&mut deserializer) } /// Deserializes `T` from `reader` pub fn from_reader<'a, T: Deserialize<'a>>(reader: impl Read + 'a) -> Result { from_reader_with_max_len(reader, DEFAULT_MAX_LEN) } /// Deserializes `T` from `reader` reading at most n bytes. pub fn from_reader_with_max_len<'a, T: Deserialize<'a>>(reader: impl Read + 'a, max_len: usize) -> Result { debug_log!( "deserialization using `from_reader_with_max_len`, max_len = {}", max_len ); let mut deserializer = Deserializer::new_from_reader(reader, max_len); T::deserialize(&mut deserializer) } /// An ASN.1-DER deserializer for `serde` pub struct Deserializer<'de> { reader: PeekableReader>, buf: Vec, encapsulator_tag_stack: Vec, header_only: bool, raw_der: bool, max_len: usize, } impl<'de> Deserializer<'de> { /// Creates a new deserializer over `bytes` pub fn new_from_bytes(bytes: &'de [u8]) -> Self { Self::new_from_reader(Cursor::new(bytes), bytes.len()) } /// Creates a new deserializer for `reader` pub fn new_from_reader(reader: impl Read + 'de, max_len: usize) -> Self { Self { reader: PeekableReader::new(Box::new(reader)), buf: Vec::new(), encapsulator_tag_stack: Vec::with_capacity(3), header_only: false, raw_der: false, max_len, } } /// Reads tag and length of the next DER object fn h_next_tag_len(&mut self) -> Result<(Tag, usize)> { // Read type and length let tag = Tag::from(self.reader.read_one()?); let len = Length::deserialized(&mut self.reader)?; Ok((tag, len)) } /// Reads the next DER object into `self.buf` and returns the tag fn h_next_object(&mut self) -> Result { let (tag, len) = match self.h_decapsulate()? { Some((tag, len)) if tag.is_primitive() && !tag.is_universal() => (tag, len), _ => { if self.raw_der { self.raw_der = false; let peeked = self.reader.peek_buffer()?; let msg_len = Length::deserialized(&mut Cursor::new(&peeked.buffer()[1..]))?; let header_len = Length::encoded_len(msg_len) + 1; (Tag::from(peeked.buffer()[0]), header_len + msg_len) } else { let tag = Tag::from(self.reader.read_one()?); let len = Length::deserialized(&mut self.reader)?; (tag, len) } } }; debug_log!("object read: {} (len = {})", tag, len); if len > self.max_len { debug_log!("TRUNCATED DATA (invalid len: found {}, max is {})", len, self.max_len); return Err(Asn1DerError::TruncatedData); } self.buf.resize(len, 0); self.reader.read_exact(self.buf.as_mut_slice())?; debug_log!("object buffer: {:02X?}", self.buf); Ok(tag) } /// Peek next DER object tag (ignoring encapsulator) fn h_peek_object(&mut self) -> Result { if self.encapsulator_tag_stack.is_empty() { Ok(Tag::from(self.reader.peek_one()?)) } else { let peeked = self.reader.peek_buffer()?; let mut cursor = 0; for encapsulator_tag in self .encapsulator_tag_stack .iter() .filter(|tag| tag.is_constructed() || **tag == Tag::BIT_STRING || **tag == Tag::OCTET_STRING) { let encapsulator_tag = *encapsulator_tag; debug_log!("encapsulator: {}", encapsulator_tag); if peeked.len() < cursor + 2 { debug_log!("peek_object: TRUNCATED DATA (couldn't read encapsulator tag or length)"); return Err(Asn1DerError::TruncatedData); } // check tag if peeked.buffer()[cursor] != encapsulator_tag.inner() { debug_log!( "peek_object: INVALID (found {}, expected encapsulator tag {})", Tag::from(peeked.buffer()[cursor]), encapsulator_tag ); self.encapsulator_tag_stack.clear(); return Err(Asn1DerError::InvalidData); } let length = { let len = Length::deserialized(&mut Cursor::new(&peeked.buffer()[cursor + 1..]))?; Length::encoded_len(len) }; cursor = if encapsulator_tag == BitStringAsn1Container::<()>::TAG { cursor + length + 2 } else { cursor + length + 1 }; } if peeked.len() <= cursor { debug_log!("peek_object: TRUNCATED DATA (couldn't read object tag)"); return Err(Asn1DerError::TruncatedData); } Ok(Tag::from(peeked.buffer()[cursor])) } } fn h_encapsulate(&mut self, tag: Tag) { debug_log!("{} pushed as encapsulator", tag); self.encapsulator_tag_stack.push(tag); } fn h_decapsulate(&mut self) -> Result> { if self.encapsulator_tag_stack.is_empty() { Ok(None) } else { let mut tag = Tag::NULL; let mut len = 0; for encapsulator_tag in &self.encapsulator_tag_stack { let encapsulator_tag = *encapsulator_tag; tag = Tag::from(self.reader.peek_one()?); if tag == encapsulator_tag { self.reader.read_one()?; // discard it } else { debug_log!( "decapsulate: INVALID (found {}, expected encapsulator tag {})", tag, encapsulator_tag ); // we need to clear the stack otherwise it'll contain unwanted tags on the next serialization self.encapsulator_tag_stack.clear(); return Err(Asn1DerError::InvalidData); } len = Length::deserialized(&mut self.reader)?; if encapsulator_tag == Tag::BIT_STRING { self.reader.read_one()?; // unused bits count } } self.encapsulator_tag_stack.clear(); Ok(Some((tag, len))) } } } impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> { type Error = Asn1DerError; fn is_human_readable(&self) -> bool { false } fn deserialize_any>(self, visitor: V) -> Result { debug_log!("deserialize_any"); match self.h_peek_object()? { Tag::BOOLEAN => self.deserialize_bool(visitor), Tag::INTEGER => { debug_log!("deserialize_any: can't be used on INTEGER"); Err(Asn1DerError::InvalidData) } Tag::NULL => self.deserialize_unit(visitor), Tag::OCTET_STRING => self.deserialize_byte_buf(visitor), Tag::SEQUENCE => self.deserialize_seq(visitor), Tag::UTF8_STRING => self.deserialize_string(visitor), Tag::BMP_STRING => self.deserialize_string(visitor), Tag::OID => self.deserialize_bytes(visitor), Tag::BIT_STRING => self.deserialize_byte_buf(visitor), Tag::UTC_TIME => self.deserialize_bytes(visitor), Tag::GENERALIZED_TIME => self.deserialize_bytes(visitor), Tag::PRINTABLE_STRING => self.deserialize_byte_buf(visitor), Tag::NUMERIC_STRING => self.deserialize_byte_buf(visitor), Tag::IA5_STRING => self.deserialize_byte_buf(visitor), Tag::GENERAL_STRING => self.deserialize_byte_buf(visitor), ExplicitContextTag0::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag0::<()>::NAME, visitor), ExplicitContextTag1::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag1::<()>::NAME, visitor), ExplicitContextTag2::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag2::<()>::NAME, visitor), ExplicitContextTag3::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag3::<()>::NAME, visitor), ExplicitContextTag4::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag4::<()>::NAME, visitor), ExplicitContextTag5::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag5::<()>::NAME, visitor), ExplicitContextTag6::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag6::<()>::NAME, visitor), ExplicitContextTag7::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag7::<()>::NAME, visitor), ExplicitContextTag8::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag8::<()>::NAME, visitor), ExplicitContextTag9::<()>::TAG => self.deserialize_newtype_struct(ExplicitContextTag9::<()>::NAME, visitor), ExplicitContextTag10::<()>::TAG => { self.deserialize_newtype_struct(ExplicitContextTag10::<()>::NAME, visitor) } ExplicitContextTag11::<()>::TAG => { self.deserialize_newtype_struct(ExplicitContextTag11::<()>::NAME, visitor) } ExplicitContextTag12::<()>::TAG => { self.deserialize_newtype_struct(ExplicitContextTag12::<()>::NAME, visitor) } ExplicitContextTag13::<()>::TAG => { self.deserialize_newtype_struct(ExplicitContextTag13::<()>::NAME, visitor) } ExplicitContextTag14::<()>::TAG => { self.deserialize_newtype_struct(ExplicitContextTag14::<()>::NAME, visitor) } ExplicitContextTag15::<()>::TAG => { self.deserialize_newtype_struct(ExplicitContextTag15::<()>::NAME, visitor) } ImplicitContextTag0::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag0::<()>::NAME, visitor), ImplicitContextTag1::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag1::<()>::NAME, visitor), ImplicitContextTag2::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag2::<()>::NAME, visitor), ImplicitContextTag3::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag3::<()>::NAME, visitor), ImplicitContextTag4::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag4::<()>::NAME, visitor), ImplicitContextTag5::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag5::<()>::NAME, visitor), ImplicitContextTag6::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag6::<()>::NAME, visitor), ImplicitContextTag7::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag7::<()>::NAME, visitor), ImplicitContextTag8::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag8::<()>::NAME, visitor), ImplicitContextTag9::<()>::TAG => self.deserialize_newtype_struct(ImplicitContextTag9::<()>::NAME, visitor), ImplicitContextTag10::<()>::TAG => { self.deserialize_newtype_struct(ImplicitContextTag10::<()>::NAME, visitor) } ImplicitContextTag11::<()>::TAG => { self.deserialize_newtype_struct(ImplicitContextTag11::<()>::NAME, visitor) } ImplicitContextTag12::<()>::TAG => { self.deserialize_newtype_struct(ImplicitContextTag12::<()>::NAME, visitor) } ImplicitContextTag13::<()>::TAG => { self.deserialize_newtype_struct(ImplicitContextTag13::<()>::NAME, visitor) } ImplicitContextTag14::<()>::TAG => { self.deserialize_newtype_struct(ImplicitContextTag14::<()>::NAME, visitor) } ImplicitContextTag15::<()>::TAG => { self.deserialize_newtype_struct(ImplicitContextTag15::<()>::NAME, visitor) } _ => { debug_log!("deserialize_any: INVALID"); Err(Asn1DerError::InvalidData) } } } fn deserialize_bool>(self, visitor: V) -> Result { debug_log!("deserialize_bool"); match self.h_peek_object()? { Tag::BOOLEAN => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_bool: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_bool(Boolean::deserialize(&self.buf)?) } fn deserialize_i8>(self, _visitor: V) -> Result { debug_log!("deserialize_i8: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_i16>(self, _visitor: V) -> Result { debug_log!("deserialize_i16: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_i32>(self, _visitor: V) -> Result { debug_log!("deserialize_i32: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_i64>(self, _visitor: V) -> Result { debug_log!("deserialize_i64: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_i128>(self, _visitor: V) -> Result { debug_log!("deserialize_i128: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_u8>(self, visitor: V) -> Result { debug_log!("deserialize_u8"); match self.h_peek_object()? { Tag::INTEGER => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_u8: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_u8(UnsignedInteger::deserialize(&self.buf)?) } fn deserialize_u16>(self, visitor: V) -> Result { debug_log!("deserialize_u16"); match self.h_peek_object()? { Tag::INTEGER => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_u16: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_u16(UnsignedInteger::deserialize(&self.buf)?) } fn deserialize_u32>(self, visitor: V) -> Result { debug_log!("deserialize_u32"); match self.h_peek_object()? { Tag::INTEGER => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_u32: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_u32(UnsignedInteger::deserialize(&self.buf)?) } fn deserialize_u64>(self, visitor: V) -> Result { debug_log!("deserialize_u64"); match self.h_peek_object()? { Tag::INTEGER => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_u64: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_u64(UnsignedInteger::deserialize(&self.buf)?) } fn deserialize_u128>(self, visitor: V) -> Result { debug_log!("deserialize_u128"); match self.h_peek_object()? { Tag::INTEGER => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_u128: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_u128(UnsignedInteger::deserialize(&self.buf)?) } fn deserialize_f32>(self, _visitor: V) -> Result { debug_log!("deserialize_f32: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_f64>(self, _visitor: V) -> Result { debug_log!("deserialize_f64: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_char>(self, visitor: V) -> Result { debug_log!("deserialize_char"); match self.h_peek_object()? { Tag::UTF8_STRING => {} Tag::BMP_STRING => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_char: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; let s = Utf8String::deserialize(&self.buf)?; let c = s.chars().next().ok_or(Asn1DerError::UnsupportedValue)?; visitor.visit_char(c) } fn deserialize_str>(self, visitor: V) -> Result { debug_log!("deserialize_str"); match self.h_peek_object()? { Tag::UTF8_STRING => {} Tag::BMP_STRING => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_str: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_str(Utf8String::deserialize(&self.buf)?) } fn deserialize_string>(self, visitor: V) -> Result { debug_log!("deserialize_string"); match self.h_peek_object()? { Tag::UTF8_STRING => {} Tag::BMP_STRING => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_string: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_string(Utf8String::deserialize(&self.buf)?.to_string()) } fn deserialize_bytes>(self, visitor: V) -> Result { debug_log!("deserialize_bytes"); match self.h_peek_object()? { Tag::OCTET_STRING => {} Tag::OID => {} Tag::BIT_STRING => {} Tag::INTEGER => {} Tag::UTC_TIME => {} Tag::GENERALIZED_TIME => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { if self.header_only { self.header_only = false; self.buf.resize(2, 0); self.reader.read_exact(&mut self.buf)?; return visitor.visit_bytes(&self.buf); } debug_log!("deserialize_bytes: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_bytes(&self.buf) } fn deserialize_byte_buf>(self, visitor: V) -> Result { debug_log!("deserialize_byte_buf"); match self.h_peek_object()? { Tag::OCTET_STRING => {} Tag::BIT_STRING => {} Tag::INTEGER => {} Tag::UTF8_STRING => {} Tag::BMP_STRING => {} Tag::PRINTABLE_STRING => {} Tag::NUMERIC_STRING => {} Tag::IA5_STRING => {} Tag::GENERAL_STRING => {} tag if (tag.is_primitive() && !tag.is_universal()) || self.raw_der => {} _tag => { debug_log!("deserialize_byte_buf: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; visitor.visit_byte_buf(self.buf.to_vec()) } fn deserialize_option>(self, visitor: V) -> Result { debug_log!("deserialize_option"); visitor.visit_some(self) } fn deserialize_unit>(self, visitor: V) -> Result { debug_log!("deserialize_unit"); match self.h_peek_object()? { Tag::NULL => {} tag if tag.is_primitive() && !tag.is_universal() => {} _tag => { debug_log!("deserialize_unit: INVALID (found {})", _tag); return Err(Asn1DerError::InvalidData); } } self.h_next_object()?; Null::deserialize(&self.buf)?; visitor.visit_unit() } fn deserialize_unit_struct>(self, _name: &'static str, visitor: V) -> Result { debug_log!("deserialize_unit_struct"); self.deserialize_unit(visitor) } fn deserialize_newtype_struct>(self, name: &'static str, visitor: V) -> Result { debug_log!("deserialize_newtype_struct: {}", name); match name { BitStringAsn1Container::<()>::NAME => self.h_encapsulate(Tag::BIT_STRING), OctetStringAsn1Container::<()>::NAME => self.h_encapsulate(Tag::OCTET_STRING), ExplicitContextTag0::<()>::NAME => self.h_encapsulate(ExplicitContextTag0::<()>::TAG), ExplicitContextTag1::<()>::NAME => self.h_encapsulate(ExplicitContextTag1::<()>::TAG), ExplicitContextTag2::<()>::NAME => self.h_encapsulate(ExplicitContextTag2::<()>::TAG), ExplicitContextTag3::<()>::NAME => self.h_encapsulate(ExplicitContextTag3::<()>::TAG), ExplicitContextTag4::<()>::NAME => self.h_encapsulate(ExplicitContextTag4::<()>::TAG), ExplicitContextTag5::<()>::NAME => self.h_encapsulate(ExplicitContextTag5::<()>::TAG), ExplicitContextTag6::<()>::NAME => self.h_encapsulate(ExplicitContextTag6::<()>::TAG), ExplicitContextTag7::<()>::NAME => self.h_encapsulate(ExplicitContextTag7::<()>::TAG), ExplicitContextTag8::<()>::NAME => self.h_encapsulate(ExplicitContextTag8::<()>::TAG), ExplicitContextTag9::<()>::NAME => self.h_encapsulate(ExplicitContextTag9::<()>::TAG), ExplicitContextTag10::<()>::NAME => self.h_encapsulate(ExplicitContextTag10::<()>::TAG), ExplicitContextTag11::<()>::NAME => self.h_encapsulate(ExplicitContextTag11::<()>::TAG), ExplicitContextTag12::<()>::NAME => self.h_encapsulate(ExplicitContextTag12::<()>::TAG), ExplicitContextTag13::<()>::NAME => self.h_encapsulate(ExplicitContextTag13::<()>::TAG), ExplicitContextTag14::<()>::NAME => self.h_encapsulate(ExplicitContextTag14::<()>::TAG), ExplicitContextTag15::<()>::NAME => self.h_encapsulate(ExplicitContextTag15::<()>::TAG), ImplicitContextTag0::<()>::NAME => self.h_encapsulate(ImplicitContextTag0::<()>::TAG), ImplicitContextTag1::<()>::NAME => self.h_encapsulate(ImplicitContextTag1::<()>::TAG), ImplicitContextTag2::<()>::NAME => self.h_encapsulate(ImplicitContextTag2::<()>::TAG), ImplicitContextTag3::<()>::NAME => self.h_encapsulate(ImplicitContextTag3::<()>::TAG), ImplicitContextTag4::<()>::NAME => self.h_encapsulate(ImplicitContextTag4::<()>::TAG), ImplicitContextTag5::<()>::NAME => self.h_encapsulate(ImplicitContextTag5::<()>::TAG), ImplicitContextTag6::<()>::NAME => self.h_encapsulate(ImplicitContextTag6::<()>::TAG), ImplicitContextTag7::<()>::NAME => self.h_encapsulate(ImplicitContextTag7::<()>::TAG), ImplicitContextTag8::<()>::NAME => self.h_encapsulate(ImplicitContextTag8::<()>::TAG), ImplicitContextTag9::<()>::NAME => self.h_encapsulate(ImplicitContextTag9::<()>::TAG), ImplicitContextTag10::<()>::NAME => self.h_encapsulate(ImplicitContextTag10::<()>::TAG), ImplicitContextTag11::<()>::NAME => self.h_encapsulate(ImplicitContextTag11::<()>::TAG), ImplicitContextTag12::<()>::NAME => self.h_encapsulate(ImplicitContextTag12::<()>::TAG), ImplicitContextTag13::<()>::NAME => self.h_encapsulate(ImplicitContextTag13::<()>::TAG), ImplicitContextTag14::<()>::NAME => self.h_encapsulate(ImplicitContextTag14::<()>::TAG), ImplicitContextTag15::<()>::NAME => self.h_encapsulate(ImplicitContextTag15::<()>::TAG), HeaderOnly::<()>::NAME => self.header_only = true, Asn1RawDer::NAME => self.raw_der = true, _ => {} } visitor.visit_newtype_struct(self) } fn deserialize_seq>(self, visitor: V) -> Result { debug_log!("deserialize_seq"); self.h_decapsulate()?; // Read tag and length let (tag, len) = self.h_next_tag_len()?; debug_log!("tag: {}, len: {}", tag, len); if !tag.is_constructed() { debug_log!("deserialize_seq: INVALID (found {})", tag); return Err(Asn1DerError::InvalidData); } visitor.visit_seq(Sequence::deserialize_lazy(self, len)) } fn deserialize_tuple>(self, _len: usize, visitor: V) -> Result { debug_log!("deserialize_tuple: {}", _len); self.deserialize_seq(visitor) } fn deserialize_tuple_struct>( self, _name: &'static str, _len: usize, visitor: V, ) -> Result { debug_log!("deserialize_tuple_struct: {}({})", _name, _len); self.deserialize_seq(visitor) } fn deserialize_map>(self, _visitor: V) -> Result { debug_log!("deserialize_map: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn deserialize_struct>( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result { debug_log!("deserialize_struct: {}", _name); self.deserialize_seq(visitor) } fn deserialize_enum>( self, _name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result { debug_log!("deserialize_enum: deserialize sequence as choice"); let peeked = self.reader.peek_buffer()?; if peeked.len() < 2 { debug_log!("TRUNCATED DATA (couldn't read length)"); return Err(Asn1DerError::TruncatedData); } let payload_len = Length::deserialized(&mut Cursor::new(&peeked.buffer()[1..]))?; let len = 1 + payload_len + Length::encoded_len(payload_len); visitor.visit_seq(Sequence::deserialize_lazy(self, len)) } fn deserialize_identifier>(self, visitor: V) -> Result { debug_log!("deserialize_identifier: peek next tag id"); let tag = self.h_peek_object()?; debug_log!("next tag id: {}", tag); visitor.visit_u8(tag.inner()) } fn deserialize_ignored_any>(self, visitor: V) -> Result { debug_log!("deserialize_ignored_any"); // Skip tag self.reader.read_one()?; // Read len and copy payload into `self.buf` let len = Length::deserialized(&mut self.reader)?; self.buf.resize(len, 0); self.reader.read_exact(&mut self.buf)?; visitor.visit_unit() } } picky-asn1-der-0.4.0/src/de/null.rs000064400000000000000000000004660072674642500151110ustar 00000000000000use crate::{Asn1DerError, Result}; /// A deserializer for the `Null` type pub struct Null; impl Null { /// Deserializes `Null` from `data` pub fn deserialize(data: &[u8]) -> Result<()> { if !data.is_empty() { return Err(Asn1DerError::InvalidData); } Ok(()) } } picky-asn1-der-0.4.0/src/de/sequence.rs000064400000000000000000000022260072674642500157430ustar 00000000000000use crate::de::Deserializer; use crate::{Asn1DerError, Result}; use serde::de::{DeserializeSeed, SeqAccess}; /// A deserializer for sequences pub struct Sequence<'a, 'de> { de: &'a mut Deserializer<'de>, len: usize, } impl<'a, 'de> Sequence<'a, 'de> { /// Creates a lazy deserializer that can walk through the sequence's sub-elements pub fn deserialize_lazy(de: &'a mut Deserializer<'de>, len: usize) -> Self { Self { de, len } } } impl<'a, 'de> SeqAccess<'de> for Sequence<'a, 'de> { type Error = Asn1DerError; fn next_element_seed>(&mut self, seed: T) -> Result> { // Check if there are still some data remaining if self.len == 0 { return Ok(None); } // Deserialize the element let pos = self.de.reader.pos(); let element = seed.deserialize(&mut *self.de)?; let read = self.de.reader.pos() - pos; if self.len < read { debug_log!("TRUNCATED DATA (read more than necessary??)"); return Err(Asn1DerError::TruncatedData); } self.len -= read; Ok(Some(element)) } } picky-asn1-der-0.4.0/src/de/utf8_string.rs000064400000000000000000000004550072674642500164110ustar 00000000000000use crate::{Asn1DerError, Result}; use std::str; /// A deserializer for UTF-8 strings pub struct Utf8String; impl Utf8String { /// The deserialized string for `data` pub fn deserialize(data: &[u8]) -> Result<&str> { str::from_utf8(data).map_err(|_| Asn1DerError::InvalidData) } } picky-asn1-der-0.4.0/src/debug_log.rs000064400000000000000000000027500072674642500154740ustar 00000000000000#[cfg(not(feature = "debug_log"))] macro_rules! debug_log { () => {}; ($($arg:tt)*) => {}; } #[cfg(feature = "debug_log")] #[macro_use] pub mod internal { use std::collections::HashMap; use std::sync::Mutex; use std::thread::ThreadId; lazy_static::lazy_static! { pub static ref CTX: Mutex> = Mutex::new(HashMap::new()); } pub struct Identer; impl Identer { pub fn ident() -> Identer { CTX.lock() .unwrap() .entry(::std::thread::current().id()) .and_modify(|c| *c += 1) .or_insert(1); Self } } impl Drop for Identer { fn drop(&mut self) { CTX.lock() .unwrap() .entry(::std::thread::current().id()) .and_modify(|c| *c -= 1); } } macro_rules! debug_log { () => { println!("| debug |"); }; ($($arg:tt)*) => { let indent = *$crate::debug_log::internal::CTX.lock() .unwrap() .get(&::std::thread::current().id()) .unwrap_or(&0); let mut blanks = String::with_capacity(indent as usize); for _ in 0..indent { blanks.push_str("| "); } print!("| debug => {}", blanks); println!($($arg)*); let _identer = $crate::debug_log::internal::Identer::ident(); }; } } picky-asn1-der-0.4.0/src/lib.rs000064400000000000000000000102420072674642500143060ustar 00000000000000//! [![Crates.io](https://img.shields.io/crates/v/picky-asn1-der.svg)](https://crates.io/crates/picky-asn1-der) //! [![docs.rs](https://docs.rs/picky-asn1-der/badge.svg)](https://docs.rs/picky-asn1-der) //! ![Crates.io](https://img.shields.io/crates/l/picky-asn1-der) //! //! # picky-asn1-der //! //! Portions of project [serde_asn1_der](https://github.com/KizzyCode/serde_asn1_der) are held by //! Keziah Biermann, 2019 as part of this project. //! //! This crate implements an ASN.1-DER subset for serde. //! //! The following types have built-in support: //! - `bool`: The ASN.1-BOOLEAN-type //! - `u8`, `u16`, `u32`, `u64`, `u128`, `usize`: The ASN.1-INTEGER-type //! - `()`: The ASN.1-NULL-type //! - `&[u8]`, `Vec`: The ASN.1-OctetString-type //! - `&str`, `String`: The ASN.1-UTF8String-type //! //! More advanced types are supported through wrappers: //! - Integer (as big integer) //! - Bit String //! - Object Identifier //! - Utf8 String //! - Numeric String //! - Printable String //! - IA5 String //! - Generalized Time //! - UTC Time //! - Application Tags from 0 to 15 //! - Context Tags from 0 to 15 //! //! Everything sequence-like combined out of this types is also supported out of the box. //! //! ```rust //! use serde::{Serialize, Deserialize}; //! //! #[derive(Serialize, Deserialize)] // Now our struct supports all DER-conversion-traits //! struct Address { //! street: String, //! house_number: u128, //! postal_code: u128, //! state: String, //! country: String //! } //! //! #[derive(Serialize, Deserialize)] // Now our struct supports all DER-conversion-traits too //! struct Customer { //! name: String, //! e_mail_address: String, //! postal_address: Address //! } //! ``` //! //! //! # Example //! ```rust //! use serde::{Serialize, Deserialize}; //! //! #[derive(Serialize, Deserialize)] //! struct TestStruct { //! number: u8, //! #[serde(with = "serde_bytes")] //! vec: Vec, //! tuple: (usize, ()) //! } //! //! let plain = TestStruct{ number: 7, vec: b"Testolope".to_vec(), tuple: (4, ()) }; //! let serialized = picky_asn1_der::to_vec(&plain).unwrap(); //! let deserialized: TestStruct = picky_asn1_der::from_bytes(&serialized).unwrap(); //! ``` #[macro_use] mod debug_log; pub mod application_tag; mod de; pub(crate) mod misc; mod raw_der; mod ser; pub use crate::de::{from_bytes, from_reader, from_reader_with_max_len, Deserializer}; pub use crate::raw_der::Asn1RawDer; pub use crate::ser::{to_byte_buf, to_bytes, to_vec, to_writer, Serializer}; use std::error::Error; use std::fmt::{self, Display, Formatter}; use std::io; /// A `picky_asn1_der`-related error #[derive(Debug)] pub enum Asn1DerError { /// The data is truncated TruncatedData, /// The data is invalid InvalidData, /// The value may be valid but is unsupported (e.g. an integer that is too large) UnsupportedValue, /// The data type is not supported by the (de-)serializer UnsupportedType, /// The provided sink is unable to accept all bytes InvalidSink, /// A custom message produced by `serde` Message(String), /// Some other underlying error (e.g. an IO error) Other(Box), } impl Display for Asn1DerError { fn fmt(&self, t: &mut Formatter) -> fmt::Result { write!(t, "{:?}", self) } } impl Error for Asn1DerError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { Asn1DerError::Other(source) => Some(source.as_ref()), _ => None, } } } impl serde::de::Error for Asn1DerError { fn custom(msg: T) -> Self { Asn1DerError::Message(msg.to_string()) } } impl serde::ser::Error for Asn1DerError { fn custom(msg: T) -> Self { Asn1DerError::Message(msg.to_string()) } } impl From for Asn1DerError { fn from(io_error: io::Error) -> Self { match io_error.kind() { io::ErrorKind::UnexpectedEof => Asn1DerError::TruncatedData, io::ErrorKind::WriteZero => Asn1DerError::InvalidSink, _ => Asn1DerError::Other(Box::new(io_error)), } } } pub type Result = std::result::Result; picky-asn1-der-0.4.0/src/misc.rs000064400000000000000000000152040072674642500144760ustar 00000000000000use crate::Asn1DerError; use std::io::{self, Read, Write}; use std::mem::size_of; /// The byte size of an `usize` const USIZE_LEN: usize = size_of::(); /// An extension for `io::Read` pub trait ReadExt { /// Reads the next byte fn read_one(&mut self) -> io::Result; } impl ReadExt for T { fn read_one(&mut self) -> io::Result { let mut buf = [0]; self.read_exact(&mut buf)?; Ok(buf[0]) } } /// An extension for `io::Write` pub trait WriteExt { /// Writes on `byte` fn write_one(&mut self, byte: u8) -> io::Result; /// Writes all bytes in `data` fn write_exact(&mut self, data: &[u8]) -> io::Result; } impl WriteExt for T { fn write_one(&mut self, byte: u8) -> io::Result { self.write_exact(&[byte]) } fn write_exact(&mut self, data: &[u8]) -> io::Result { self.write_all(data)?; Ok(data.len()) } } const PEEKED_BUFFER_SIZE: usize = 10; #[derive(Debug)] pub struct PeekedContent { len: usize, buffer: [u8; PEEKED_BUFFER_SIZE], } impl PeekedContent { fn new() -> Self { Self { len: 0, buffer: [0; PEEKED_BUFFER_SIZE], } } pub fn take(&mut self) -> Self { let mut val = Self::new(); std::mem::swap(&mut val, self); val } pub fn len(&self) -> usize { self.len } pub fn buffer(&self) -> [u8; PEEKED_BUFFER_SIZE] { self.buffer } } /// A peekable reader pub struct PeekableReader { reader: R, peeked: PeekedContent, pos: usize, } impl PeekableReader { /// Creates a new `PeekableReader` with `reader` as source pub fn new(reader: R) -> Self { Self { reader, peeked: PeekedContent::new(), pos: 0, } } /// Peeks one byte without removing it from the `read`-queue /// /// Multiple successive calls to `peek_one` will always return the same next byte pub fn peek_one(&mut self) -> io::Result { // Check if we already have peeked data if self.peeked.len == 0 { self.peeked.buffer[0] = self.reader.read_one()?; self.peeked.len = 1; } Ok(self.peeked.buffer[0]) } /// Peeks several bytes at once without removing them from the `read`-queue /// Buffer size is defined by `PeekedBuffer`. /// /// Successive calls to `peek_buffer` always return the same bytes. pub fn peek_buffer(&mut self) -> io::Result<&PeekedContent> { // Check if we already have peeked data if self.peeked.len < PEEKED_BUFFER_SIZE { let n = self.reader.read(&mut self.peeked.buffer[self.peeked.len..])?; self.peeked.len += n; } Ok(&self.peeked) } /// The current position (amount of bytes read) pub fn pos(&self) -> usize { self.pos } } impl Read for PeekableReader { fn read(&mut self, mut buf: &mut [u8]) -> io::Result { let mut read = 0; let peeked = self.peeked.take(); let new_start_index = if buf.len() <= peeked.len { buf.copy_from_slice(&peeked.buffer[..buf.len()]); // keep remaining peeked bytes let remaining_bytes = peeked.len - buf.len(); if remaining_bytes > 0 { self.peeked.buffer[..remaining_bytes].copy_from_slice(&peeked.buffer[buf.len()..peeked.len]); self.peeked.len = remaining_bytes; } buf.len() } else { buf[..peeked.len].copy_from_slice(&peeked.buffer[..peeked.len]); peeked.len }; read += new_start_index; buf = &mut buf[new_start_index..]; // Read remaining bytes read += self.reader.read(buf)?; self.pos += read; Ok(read) } } /// An implementation of the ASN.1-DER length pub struct Length; impl Length { /// Deserializes a length from `reader` pub fn deserialized(mut reader: impl Read) -> Result { // Deserialize length Ok(match reader.read_one()? { n @ 128..=255 => { // Deserialize the amount of length bytes let len = n as usize & 127; if len > USIZE_LEN { return Err(Asn1DerError::UnsupportedValue); } // Deserialize value let mut num = [0; USIZE_LEN]; reader.read_exact(&mut num[USIZE_LEN - len..])?; usize::from_be_bytes(num) } n => n as usize, }) } /// Serializes `len` to `writer` pub fn serialize(len: usize, mut writer: impl Write) -> Result { // Determine the serialized length let written = match len { 0..=127 => writer.write_one(len as u8)?, _ => { let to_write = USIZE_LEN - (len.leading_zeros() / 8) as usize; // Write number of bytes used to encode length let mut written = writer.write_one(to_write as u8 | 0x80)?; // Write length let mut buf = [0; USIZE_LEN]; buf.copy_from_slice(&len.to_be_bytes()); written += writer.write_exact(&buf[USIZE_LEN - to_write..])?; written } }; Ok(written) } /// Returns how many bytes are going to be needed to encode `len`. pub fn encoded_len(len: usize) -> usize { match len { 0..=127 => 1, _ => 1 + USIZE_LEN - (len.leading_zeros() / 8) as usize, } } } #[cfg(test)] mod tests { use super::*; #[test] fn asn1_short_form_length() { let mut writer: Vec = Vec::new(); let written = Length::serialize(10, &mut writer).expect("serialization failed"); assert_eq!(written, 1); assert_eq!(writer.len(), 1); assert_eq!(writer[0], 10); } #[test] fn asn1_long_form_length_1_byte() { let mut writer: Vec = Vec::new(); let written = Length::serialize(129, &mut writer).expect("serialization failed"); assert_eq!(written, 2); assert_eq!(writer.len(), 2); assert_eq!(writer[0], 0x81); assert_eq!(writer[1], 0x81); } #[test] fn asn1_long_form_length_2_bytes() { let mut writer: Vec = Vec::new(); let written = Length::serialize(290, &mut writer).expect("serialization failed"); assert_eq!(written, 3); assert_eq!(writer.len(), 3); assert_eq!(writer[0], 0x82); assert_eq!(writer[1], 0x01); assert_eq!(writer[2], 0x22); } } picky-asn1-der-0.4.0/src/raw_der.rs000064400000000000000000000044230072674642500151670ustar 00000000000000use serde::{Deserialize, Serialize}; /// User-provided raw DER wrapper. /// /// Allow user to provide raw DER: no tag is added by serializer and bytes are bumped as it. /// Note that provided DER header has to be valid to determine length on deserialization. /// /// # Example /// ``` /// use picky_asn1_der::Asn1RawDer; /// use serde::{Serialize, Deserialize}; /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct A { /// number: u8, /// user_provided: Asn1RawDer, /// } /// /// let plain_a = A { /// number: 7, /// user_provided: Asn1RawDer(vec![ /// 0x30, 0x08, /// 0x0C, 0x03, 0x41, 0x62, 0x63, /// 0x02, 0x01, 0x05, /// ]), /// }; /// /// let serialized_a = picky_asn1_der::to_vec(&plain_a).expect("A to vec"); /// assert_eq!( /// serialized_a, /// [ /// 0x30, 0x0D, /// 0x02, 0x01, 0x07, /// 0x30, 0x08, /// 0x0C, 0x03, 0x41, 0x62, 0x63, /// 0x02, 0x01, 0x05, /// ] /// ); /// /// let deserialized_a = picky_asn1_der::from_bytes(&serialized_a).expect("A from bytes"); /// assert_eq!(plain_a, deserialized_a); /// /// // we can deserialize into a compatible B structure. /// /// #[derive(Deserialize, Debug, PartialEq)] /// struct B { /// number: u8, /// tuple: (String, u8), /// } /// /// let plain_b = B { number: 7, tuple: ("Abc".to_owned(), 5) }; /// let deserialized_b: B = picky_asn1_der::from_bytes(&serialized_a).expect("B from bytes"); /// assert_eq!(deserialized_b, plain_b); /// ``` #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Hash, Clone)] pub struct Asn1RawDer(#[serde(with = "serde_bytes")] pub Vec); impl Asn1RawDer { pub const NAME: &'static str = "Asn1RawDer"; } #[cfg(test)] mod tests { use super::*; use picky_asn1::wrapper::ExplicitContextTag0; #[test] fn raw_der_behind_application_tag() { let encoded = crate::to_vec(&ExplicitContextTag0(Asn1RawDer(vec![0x02, 0x01, 0x07]))).expect("to vec"); pretty_assertions::assert_eq!(encoded.as_slice(), [0xA0, 0x03, 0x02, 0x01, 0x07]); let decoded: ExplicitContextTag0 = crate::from_bytes(&encoded).expect("from bytes"); pretty_assertions::assert_eq!((decoded.0).0.as_slice(), [0x02, 0x01, 0x07]); } } picky-asn1-der-0.4.0/src/ser/boolean.rs000064400000000000000000000010230072674642500157450ustar 00000000000000use crate::misc::WriteExt; use crate::{Result, Serializer}; use picky_asn1::tag::Tag; /// A serializer for booleans pub struct Boolean; impl Boolean { /// Serializes `value` into `writer` pub fn serialize(value: bool, ser: &mut Serializer) -> Result { let mut written = ser.h_write_header(Tag::BOOLEAN, 1)?; // Serialize the value written += if value { ser.writer.write_one(0xff)? } else { ser.writer.write_one(0x00)? }; Ok(written) } } picky-asn1-der-0.4.0/src/ser/integer.rs000064400000000000000000000023760072674642500157770ustar 00000000000000use crate::misc::WriteExt; use crate::{Result, Serializer}; use picky_asn1::tag::Tag; /// A trait that allows you to map all unsigned integers to a `u128` pub trait UInt: Sized + Copy { /// Converts `self` into a `u128` fn into_u128(self) -> u128; } macro_rules! impl_uint { ($type:ident) => { impl UInt for $type { fn into_u128(self) -> u128 { self as u128 } } }; ($($type:ident),+) => ($( impl_uint!($type); )+) } impl_uint!(usize, u128, u64, u32, u16, u8); /// A serializer for unsigned integers pub struct UnsignedInteger; impl UnsignedInteger { /// Serializes `value` into `writer` pub fn serialize(value: T, ser: &mut Serializer) -> Result { // Convert the value and compute the amount of bytes to skip let value = value.into_u128(); let skip = match value.leading_zeros() as usize { n if n % 8 == 0 => n / 8, n => (n / 8) + 1, }; let length = 17 - skip; let mut written = ser.h_write_header(Tag::INTEGER, length)?; // Serialize the value and write the bytes let mut bytes = [0; 17]; bytes[1..].copy_from_slice(&value.to_be_bytes()); written += ser.writer.write_exact(&bytes[skip..])?; Ok(written) } } picky-asn1-der-0.4.0/src/ser/mod.rs000064400000000000000000000412500072674642500151130ustar 00000000000000mod boolean; mod integer; mod null; mod sequence; mod utf8_string; use crate::misc::{Length, WriteExt}; use crate::ser::boolean::Boolean; use crate::ser::integer::UnsignedInteger; use crate::ser::null::Null; use crate::ser::sequence::Sequence; use crate::ser::utf8_string::Utf8String; use crate::{Asn1DerError, Asn1RawDer, Result}; use picky_asn1::tag::Tag; use picky_asn1::wrapper::*; use picky_asn1::Asn1Type; use serde::Serialize; use std::io::{Cursor, Write}; /// Serializes `value` pub fn to_vec(value: &T) -> Result> { let mut buf = Vec::new(); to_byte_buf(value, &mut buf)?; Ok(buf) } /// Serializes `value` to `buf` and returns the amount of serialized bytes pub fn to_bytes(value: &T, buf: &mut [u8]) -> Result { debug_log!("serialization using `to_bytes`"); let mut serializer = Serializer::new_to_bytes(buf); value.serialize(&mut serializer) } /// Serializes `value` to `buf` and returns the amount of serialized bytes pub fn to_byte_buf(value: &T, buf: &mut Vec) -> Result { debug_log!("serialization using `to_byte_buf`"); let mut serializer = Serializer::new_to_byte_buf(buf); value.serialize(&mut serializer) } /// Serializes `value` to `writer` and returns the amount of serialized bytes pub fn to_writer(value: &T, writer: impl Write) -> Result { debug_log!("serialization using `to_writer`"); let mut serializer = Serializer::new_to_writer(writer); value.serialize(&mut serializer) } /// An ASN.1-DER serializer for `serde` pub struct Serializer<'se> { writer: Box, tag_for_next_bytes: Tag, tag_for_next_seq: Tag, encapsulators: Vec, no_header: bool, } impl<'se> Serializer<'se> { /// Creates a new serializer that writes to `buf` pub fn new_to_bytes(buf: &'se mut [u8]) -> Self { Self::new_to_writer(Cursor::new(buf)) } /// Creates a new serializer that writes to `buf` pub fn new_to_byte_buf(buf: &'se mut Vec) -> Self { Self::new_to_writer(Cursor::new(buf)) } /// Creates a new serializer that writes to `writer` pub fn new_to_writer(writer: impl Write + 'se) -> Self { Self { writer: Box::new(writer), tag_for_next_bytes: Tag::OCTET_STRING, tag_for_next_seq: Tag::SEQUENCE, encapsulators: Vec::with_capacity(3), no_header: false, } } fn h_encapsulate(&mut self, tag: Tag) { self.encapsulators.push(tag); } fn h_write_encapsulator(&mut self, payload_len: usize) -> Result { let mut written = 0; for (i, encapsulator_tag) in self.encapsulators.iter().copied().enumerate() { written += self.writer.write_one(encapsulator_tag.inner())?; let encapsulated_len = { let mut encapsulated_len = payload_len; for sub_encapsulator_tag in self.encapsulators.iter().skip(i + 1).copied().rev() { if sub_encapsulator_tag == BitStringAsn1Container::<()>::TAG { encapsulated_len += Length::encoded_len(encapsulated_len + 1) + 1; } else { encapsulated_len += Length::encoded_len(encapsulated_len) + 1; } } encapsulated_len }; if encapsulator_tag == BitStringAsn1Container::<()>::TAG { written += Length::serialize(encapsulated_len + 1, &mut self.writer)?; written += self.writer.write_one(0x00)?; // no unused bits } else { written += Length::serialize(encapsulated_len, &mut self.writer)?; } } self.encapsulators.clear(); Ok(written) } fn h_write_header(&mut self, tag: Tag, len: usize) -> Result { let mut written; match self.encapsulators.last() { Some(last_encapsulator_tag) if last_encapsulator_tag.is_context_specific() && last_encapsulator_tag.is_primitive() => { written = self.h_write_encapsulator(len)?; } _ => { if self.no_header { written = self.h_write_encapsulator(len)?; } else { written = self.h_write_encapsulator(Length::encoded_len(len) + len + 1)?; written += self.writer.write_one(tag.inner())?; written += Length::serialize(len, &mut self.writer)?; } } } self.no_header = false; // reset state Ok(written) } fn h_serialize_bytes_with_tag(&mut self, bytes: &[u8]) -> Result { let mut written = self.h_write_header(self.tag_for_next_bytes, bytes.len())?; written += self.writer.write_exact(bytes)?; self.tag_for_next_bytes = Tag::OCTET_STRING; // reset to octet string Ok(written) } } impl<'a, 'se> serde::ser::Serializer for &'a mut Serializer<'se> { type Ok = usize; type Error = Asn1DerError; type SerializeSeq = Sequence<'a, 'se>; type SerializeTuple = Sequence<'a, 'se>; type SerializeTupleStruct = Sequence<'a, 'se>; type SerializeTupleVariant = Self; type SerializeMap = Self; type SerializeStruct = Sequence<'a, 'se>; type SerializeStructVariant = Self; fn is_human_readable(&self) -> bool { false } fn serialize_bool(self, v: bool) -> Result { debug_log!("serialize_bool: {}", v); Boolean::serialize(v, self) } fn serialize_i8(self, _v: i8) -> Result { debug_log!("serialize_i8: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_i16(self, _v: i16) -> Result { debug_log!("serialize_i16: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_i32(self, _v: i32) -> Result { debug_log!("serialize_i32: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_i64(self, _v: i64) -> Result { debug_log!("serialize_i64: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_i128(self, _v: i128) -> Result { debug_log!("serialize_i128: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_u8(self, v: u8) -> Result { debug_log!("serialize_u8: {}", v); self.serialize_u128(v as u128) } fn serialize_u16(self, v: u16) -> Result { debug_log!("serialize_u16: {}", v); self.serialize_u128(v as u128) } fn serialize_u32(self, v: u32) -> Result { debug_log!("serialize_u32: {}", v); self.serialize_u128(v as u128) } fn serialize_u64(self, v: u64) -> Result { debug_log!("serialize_u64: {}", v); self.serialize_u128(v as u128) } fn serialize_u128(self, v: u128) -> Result { debug_log!("serialize_u128: {}", v); UnsignedInteger::serialize(v, self) } fn serialize_f32(self, _v: f32) -> Result { debug_log!("serialize_f32: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_f64(self, _v: f64) -> Result { debug_log!("serialize_f64: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_char(self, v: char) -> Result { debug_log!("serialize_char: {}", v); let mut buf = [0; 4]; self.serialize_str(v.encode_utf8(&mut buf)) } fn serialize_str(self, v: &str) -> Result { debug_log!("serialize_str: {}", v); Utf8String::serialize(v, self) } fn serialize_bytes(self, v: &[u8]) -> Result { debug_log!("serialize_bytes"); self.h_serialize_bytes_with_tag(v) } fn serialize_none(self) -> Result { debug_log!("serialize_none"); Ok(0) } fn serialize_some(self, value: &T) -> Result { debug_log!("serialize_some"); value.serialize(self) } fn serialize_unit(self) -> Result { debug_log!("serialize_unit"); Null::serialize(self) } fn serialize_unit_struct(self, _name: &'static str) -> Result { debug_log!("serialize_unit_struct: {}", _name); Null::serialize(self) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { debug_log!("serialize_unit_variant: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_newtype_struct(mut self, name: &'static str, value: &T) -> Result { debug_log!("serialize_newtype_struct: {}", name); match name { ObjectIdentifierAsn1::NAME => self.tag_for_next_bytes = Tag::OID, BitStringAsn1::NAME => self.tag_for_next_bytes = Tag::BIT_STRING, IntegerAsn1::NAME => self.tag_for_next_bytes = Tag::INTEGER, UTCTimeAsn1::NAME => self.tag_for_next_bytes = Tag::UTC_TIME, GeneralizedTimeAsn1::NAME => self.tag_for_next_bytes = Tag::GENERALIZED_TIME, Utf8StringAsn1::NAME => self.tag_for_next_bytes = Tag::UTF8_STRING, PrintableStringAsn1::NAME => self.tag_for_next_bytes = Tag::PRINTABLE_STRING, NumericStringAsn1::NAME => self.tag_for_next_bytes = Tag::NUMERIC_STRING, IA5StringAsn1::NAME => self.tag_for_next_bytes = Tag::IA5_STRING, BMPStringAsn1::NAME => self.tag_for_next_bytes = Tag::BMP_STRING, GeneralStringAsn1::NAME => self.tag_for_next_bytes = Tag::GENERAL_STRING, Asn1SetOf::<()>::NAME => self.tag_for_next_seq = Tag::SET, Asn1SequenceOf::<()>::NAME => self.tag_for_next_seq = Tag::SEQUENCE, BitStringAsn1Container::<()>::NAME => self.h_encapsulate(Tag::BIT_STRING), OctetStringAsn1Container::<()>::NAME => self.h_encapsulate(Tag::OCTET_STRING), ExplicitContextTag0::<()>::NAME => self.h_encapsulate(ExplicitContextTag0::<()>::TAG), ExplicitContextTag1::<()>::NAME => self.h_encapsulate(ExplicitContextTag1::<()>::TAG), ExplicitContextTag2::<()>::NAME => self.h_encapsulate(ExplicitContextTag2::<()>::TAG), ExplicitContextTag3::<()>::NAME => self.h_encapsulate(ExplicitContextTag3::<()>::TAG), ExplicitContextTag4::<()>::NAME => self.h_encapsulate(ExplicitContextTag4::<()>::TAG), ExplicitContextTag5::<()>::NAME => self.h_encapsulate(ExplicitContextTag5::<()>::TAG), ExplicitContextTag6::<()>::NAME => self.h_encapsulate(ExplicitContextTag6::<()>::TAG), ExplicitContextTag7::<()>::NAME => self.h_encapsulate(ExplicitContextTag7::<()>::TAG), ExplicitContextTag8::<()>::NAME => self.h_encapsulate(ExplicitContextTag8::<()>::TAG), ExplicitContextTag9::<()>::NAME => self.h_encapsulate(ExplicitContextTag9::<()>::TAG), ExplicitContextTag10::<()>::NAME => self.h_encapsulate(ExplicitContextTag10::<()>::TAG), ExplicitContextTag11::<()>::NAME => self.h_encapsulate(ExplicitContextTag11::<()>::TAG), ExplicitContextTag12::<()>::NAME => self.h_encapsulate(ExplicitContextTag12::<()>::TAG), ExplicitContextTag13::<()>::NAME => self.h_encapsulate(ExplicitContextTag13::<()>::TAG), ExplicitContextTag14::<()>::NAME => self.h_encapsulate(ExplicitContextTag14::<()>::TAG), ExplicitContextTag15::<()>::NAME => self.h_encapsulate(ExplicitContextTag15::<()>::TAG), ImplicitContextTag0::<()>::NAME => self.h_encapsulate(ImplicitContextTag0::<()>::TAG), ImplicitContextTag1::<()>::NAME => self.h_encapsulate(ImplicitContextTag1::<()>::TAG), ImplicitContextTag2::<()>::NAME => self.h_encapsulate(ImplicitContextTag2::<()>::TAG), ImplicitContextTag3::<()>::NAME => self.h_encapsulate(ImplicitContextTag3::<()>::TAG), ImplicitContextTag4::<()>::NAME => self.h_encapsulate(ImplicitContextTag4::<()>::TAG), ImplicitContextTag5::<()>::NAME => self.h_encapsulate(ImplicitContextTag5::<()>::TAG), ImplicitContextTag6::<()>::NAME => self.h_encapsulate(ImplicitContextTag6::<()>::TAG), ImplicitContextTag7::<()>::NAME => self.h_encapsulate(ImplicitContextTag7::<()>::TAG), ImplicitContextTag8::<()>::NAME => self.h_encapsulate(ImplicitContextTag8::<()>::TAG), ImplicitContextTag9::<()>::NAME => self.h_encapsulate(ImplicitContextTag9::<()>::TAG), ImplicitContextTag10::<()>::NAME => self.h_encapsulate(ImplicitContextTag10::<()>::TAG), ImplicitContextTag11::<()>::NAME => self.h_encapsulate(ImplicitContextTag11::<()>::TAG), ImplicitContextTag12::<()>::NAME => self.h_encapsulate(ImplicitContextTag12::<()>::TAG), ImplicitContextTag13::<()>::NAME => self.h_encapsulate(ImplicitContextTag13::<()>::TAG), ImplicitContextTag14::<()>::NAME => self.h_encapsulate(ImplicitContextTag14::<()>::TAG), ImplicitContextTag15::<()>::NAME => self.h_encapsulate(ImplicitContextTag15::<()>::TAG), HeaderOnly::<()>::NAME => self.no_header = true, Asn1RawDer::NAME => self.no_header = true, _ => {} } value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result { debug_log!("serialize_newtype_variant: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_seq(self, _len: Option) -> Result { debug_log!("serialize_seq"); let mut tag = Tag::SEQUENCE; std::mem::swap(&mut tag, &mut self.tag_for_next_seq); Ok(Sequence::serialize_lazy(self, tag)) } fn serialize_tuple(self, len: usize) -> Result { debug_log!("serialize_tuple: {}", len); self.serialize_seq(Some(len)) } fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result { debug_log!("serialize_tuple_struct: {}({})", _name, len); self.serialize_seq(Some(len)) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { debug_log!("serialize_tuple_variant: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_map(self, _len: Option) -> Result { debug_log!("serialize_map: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } fn serialize_struct(self, _name: &'static str, len: usize) -> Result { debug_log!("serialize_struct: {}", _name); self.serialize_seq(Some(len)) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { debug_log!("serialize_struct_variant: UNSUPPORTED"); Err(Asn1DerError::UnsupportedType) } } impl<'a, 'se> serde::ser::SerializeTupleVariant for &'a mut Serializer<'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_field(&mut self, _value: &T) -> Result<()> { unimplemented!("The implementation does not support tuple variants") } fn end(self) -> Result { unimplemented!("The implementation does not support tuple variants") } } impl<'a, 'se> serde::ser::SerializeMap for &'a mut Serializer<'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_key(&mut self, _key: &T) -> Result<()> { unimplemented!("The implementation does not support maps") } fn serialize_value(&mut self, _value: &T) -> Result<()> { unimplemented!("The implementation does not support maps") } fn end(self) -> Result { unimplemented!("The implementation does not support maps") } } impl<'a, 'se> serde::ser::SerializeStructVariant for &'a mut Serializer<'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_field(&mut self, _key: &'static str, _value: &T) -> Result<()> { unimplemented!("The implementation does not support struct variants") } fn end(self) -> Result { unimplemented!("The implementation does not support struct variants") } } picky-asn1-der-0.4.0/src/ser/null.rs000064400000000000000000000004300072674642500153010ustar 00000000000000use crate::{Result, Serializer}; use picky_asn1::tag::Tag; /// A serializer for the `Null` type pub struct Null; impl Null { /// Serializes a `Null` into `_writer` pub fn serialize(ser: &mut Serializer) -> Result { ser.h_write_header(Tag::NULL, 0) } } picky-asn1-der-0.4.0/src/ser/sequence.rs000064400000000000000000000045420072674642500161470ustar 00000000000000use crate::misc::WriteExt; use crate::ser::{to_writer, Serializer}; use crate::{Asn1DerError, Result}; use picky_asn1::tag::Tag; use serde::Serialize; use std::io::Cursor; /// A serializer for sequences pub struct Sequence<'a, 'se> { ser: &'a mut Serializer<'se>, buf: Cursor>, tag: Tag, } impl<'a, 'se> Sequence<'a, 'se> { /// Creates a lazy serializer that will serialize the sequence's sub-elements to `writer` pub fn serialize_lazy(ser: &'a mut Serializer<'se>, tag: Tag) -> Self { Self { ser, buf: Cursor::new(Vec::new()), tag, } } /// Writes the next `value` to the internal buffer fn write_object(&mut self, value: &T) -> Result<()> { to_writer(value, &mut self.buf)?; Ok(()) } /// Finalizes the sequence fn finalize(self) -> Result { // Reclaim buffer let buf = self.buf.into_inner(); let mut written = self.ser.h_write_header(self.tag, buf.len())?; written += self.ser.writer.write_exact(&buf)?; Ok(written) } } impl<'a, 'se> serde::ser::SerializeSeq for Sequence<'a, 'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_element(&mut self, value: &T) -> Result<()> { self.write_object(value) } fn end(self) -> Result { self.finalize() } } impl<'a, 'se> serde::ser::SerializeTuple for Sequence<'a, 'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_element(&mut self, value: &T) -> Result<()> { self.write_object(value) } fn end(self) -> Result { self.finalize() } } impl<'a, 'se> serde::ser::SerializeStruct for Sequence<'a, 'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> { self.write_object(value) } fn end(self) -> Result { self.finalize() } } impl<'a, 'se> serde::ser::SerializeTupleStruct for Sequence<'a, 'se> { type Ok = usize; type Error = Asn1DerError; fn serialize_field(&mut self, value: &T) -> Result<()> { self.write_object(value) } fn end(self) -> Result { self.finalize() } } picky-asn1-der-0.4.0/src/ser/utf8_string.rs000064400000000000000000000006770072674642500166200ustar 00000000000000use crate::misc::WriteExt; use crate::{Result, Serializer}; use picky_asn1::tag::Tag; /// A serializer for UTF-8 strings pub struct Utf8String; impl Utf8String { /// Serializes `value` into `writer` pub fn serialize(value: &str, ser: &mut Serializer) -> Result { let mut written = ser.h_write_header(Tag::UTF8_STRING, value.len())?; written += ser.writer.write_exact(value.as_bytes())?; Ok(written) } }