diff --git a/der/src/asn1/any.rs b/der/src/asn1/any.rs index 140291979..b4a4e3bbd 100644 --- a/der/src/asn1/any.rs +++ b/der/src/asn1/any.rs @@ -2,7 +2,7 @@ use crate::{ asn1::*, ByteSlice, Choice, Decode, DecodeValue, Decoder, DerOrd, EncodeValue, Encoder, Error, - ErrorKind, FixedTag, Header, Length, Result, Tag, Tagged, ValueOrd, + ErrorKind, FixedTag, Header, Length, Result, Tag, Tagged, ValueOrd, Writer, }; use core::cmp::Ordering; @@ -168,7 +168,7 @@ impl EncodeValue for Any<'_> { } fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.bytes(self.value()) + encoder.write(self.value()) } } diff --git a/der/src/asn1/bit_string.rs b/der/src/asn1/bit_string.rs index 89f1d31d5..a3f39947c 100644 --- a/der/src/asn1/bit_string.rs +++ b/der/src/asn1/bit_string.rs @@ -2,7 +2,7 @@ use crate::{ asn1::Any, ByteSlice, DecodeValue, Decoder, DerOrd, EncodeValue, Encoder, Error, ErrorKind, - FixedTag, Header, Length, Result, Tag, ValueOrd, + FixedTag, Header, Length, Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, iter::FusedIterator}; @@ -134,8 +134,8 @@ impl EncodeValue for BitString<'_> { } fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.byte(self.unused_bits)?; - encoder.bytes(self.raw_bytes()) + encoder.write_byte(self.unused_bits)?; + encoder.write(self.raw_bytes()) } } diff --git a/der/src/asn1/boolean.rs b/der/src/asn1/boolean.rs index ac6e2cec8..918aa229b 100644 --- a/der/src/asn1/boolean.rs +++ b/der/src/asn1/boolean.rs @@ -2,7 +2,7 @@ use crate::{ asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, - ErrorKind, FixedTag, Header, Length, Result, Tag, + ErrorKind, FixedTag, Header, Length, Result, Tag, Writer, }; /// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1: @@ -34,7 +34,7 @@ impl EncodeValue for bool { } fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.byte(if *self { TRUE_OCTET } else { FALSE_OCTET }) + encoder.write_byte(if *self { TRUE_OCTET } else { FALSE_OCTET }) } } diff --git a/der/src/asn1/generalized_time.rs b/der/src/asn1/generalized_time.rs index 2cc7a924b..7bba7871b 100644 --- a/der/src/asn1/generalized_time.rs +++ b/der/src/asn1/generalized_time.rs @@ -5,7 +5,7 @@ use crate::{ datetime::{self, DateTime}, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, ErrorKind, FixedTag, Header, - Length, Result, Tag, + Length, Result, Tag, Writer, }; use core::time::Duration; @@ -115,7 +115,7 @@ impl EncodeValue for GeneralizedTime { datetime::encode_decimal(encoder, Self::TAG, self.0.hour())?; datetime::encode_decimal(encoder, Self::TAG, self.0.minutes())?; datetime::encode_decimal(encoder, Self::TAG, self.0.seconds())?; - encoder.byte(b'Z') + encoder.write_byte(b'Z') } } diff --git a/der/src/asn1/integer/bigint.rs b/der/src/asn1/integer/bigint.rs index 9216f5fbc..ff71d361e 100644 --- a/der/src/asn1/integer/bigint.rs +++ b/der/src/asn1/integer/bigint.rs @@ -3,7 +3,7 @@ use super::uint; use crate::{ asn1::Any, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, ErrorKind, FixedTag, - Header, Length, Result, Tag, + Header, Length, Result, Tag, Writer, }; /// "Big" unsigned ASN.1 `INTEGER` type. @@ -67,10 +67,10 @@ impl<'a> EncodeValue for UIntBytes<'a> { fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { // Add leading `0x00` byte if required if self.value_len()? > self.len() { - encoder.byte(0)?; + encoder.write_byte(0)?; } - encoder.bytes(self.as_bytes()) + encoder.write(self.as_bytes()) } } diff --git a/der/src/asn1/integer/int.rs b/der/src/asn1/integer/int.rs index 2d82e1b9c..bc6489bb7 100644 --- a/der/src/asn1/integer/int.rs +++ b/der/src/asn1/integer/int.rs @@ -1,7 +1,7 @@ //! Support for encoding negative integers use super::is_highest_bit_set; -use crate::{Encoder, ErrorKind, Length, Result}; +use crate::{Encoder, ErrorKind, Length, Result, Writer}; /// Decode an unsigned integer of the specified size. /// @@ -28,7 +28,7 @@ pub(super) fn decode_to_array(bytes: &[u8]) -> Result<[u8; N]> { /// Encode the given big endian bytes representing an integer as ASN.1 DER. pub(super) fn encode_bytes(encoder: &mut Encoder<'_>, bytes: &[u8]) -> Result<()> { - encoder.bytes(strip_leading_ones(bytes)) + encoder.write(strip_leading_ones(bytes)) } /// Get the encoded length for the given unsigned integer serialized as bytes. diff --git a/der/src/asn1/integer/uint.rs b/der/src/asn1/integer/uint.rs index a30584abd..a6e0d221e 100644 --- a/der/src/asn1/integer/uint.rs +++ b/der/src/asn1/integer/uint.rs @@ -1,6 +1,6 @@ //! Unsigned integer decoders/encoders. -use crate::{Encoder, Length, Result, Tag}; +use crate::{Encoder, Length, Result, Tag, Writer}; /// Decode an unsigned integer into a big endian byte slice with all leading /// zeroes removed. @@ -44,10 +44,10 @@ pub(crate) fn encode_bytes(encoder: &mut Encoder<'_>, bytes: &[u8]) -> Result<() let bytes = strip_leading_zeroes(bytes); if needs_leading_zero(bytes) { - encoder.byte(0)?; + encoder.write_byte(0)?; } - encoder.bytes(bytes) + encoder.write(bytes) } /// Get the encoded length for the given unsigned integer serialized as bytes. diff --git a/der/src/asn1/oid.rs b/der/src/asn1/oid.rs index e72558d9e..c464c9a7f 100644 --- a/der/src/asn1/oid.rs +++ b/der/src/asn1/oid.rs @@ -2,7 +2,7 @@ use crate::{ asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, - FixedTag, Header, Length, Result, Tag, Tagged, + FixedTag, Header, Length, Result, Tag, Tagged, Writer, }; use const_oid::ObjectIdentifier; @@ -19,7 +19,7 @@ impl EncodeValue for ObjectIdentifier { } fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.bytes(self.as_bytes()) + encoder.write(self.as_bytes()) } } diff --git a/der/src/asn1/real.rs b/der/src/asn1/real.rs index 36f30e5b7..fd6c24e42 100644 --- a/der/src/asn1/real.rs +++ b/der/src/asn1/real.rs @@ -9,7 +9,7 @@ use crate::{ str_slice::StrSlice, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, FixedTag, Header, - Length, Result, Tag, + Length, Result, Tag, Writer, }; use super::integer::uint::strip_leading_zeroes; @@ -136,18 +136,18 @@ impl EncodeValue for f64 { return Ok(()); } else if self.is_nan() { // Not a number - encoder.bytes(&[0b0100_0010])?; + encoder.write_byte(0b0100_0010)?; } else if self.is_infinite() { if self.is_sign_negative() { // Negative infinity - encoder.bytes(&[0b0100_0001])?; + encoder.write_byte(0b0100_0001)?; } else { // Plus infinity - encoder.bytes(&[0b0100_0000])?; + encoder.write_byte(0b0100_0000)?; } } else { // Minus zero - encoder.bytes(&[0b0100_0011])?; + encoder.write_byte(0b0100_0011)?; } } else { // Always use binary encoding, set bit 8 to 1 @@ -178,16 +178,16 @@ impl EncodeValue for f64 { } } - encoder.bytes(&[first_byte])?; + encoder.write_byte(first_byte)?; // Encode both bytes or just the last one, handled by encode_bytes directly // Rust already encodes the data as two's complement, so no further processing is needed - encoder.bytes(ebytes)?; + encoder.write(ebytes)?; // Now, encode the mantissa as unsigned binary number let mantissa_bytes = mantissa.to_be_bytes(); let mbytes = strip_leading_zeroes(&mantissa_bytes); - encoder.bytes(mbytes)?; + encoder.write(mbytes)?; } Ok(()) } diff --git a/der/src/asn1/utc_time.rs b/der/src/asn1/utc_time.rs index 572537014..d3f28512e 100644 --- a/der/src/asn1/utc_time.rs +++ b/der/src/asn1/utc_time.rs @@ -5,7 +5,7 @@ use crate::{ datetime::{self, DateTime}, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, ErrorKind, FixedTag, Header, - Length, Result, Tag, + Length, Result, Tag, Writer, }; use core::time::Duration; @@ -128,7 +128,7 @@ impl EncodeValue for UtcTime { datetime::encode_decimal(encoder, Self::TAG, self.0.hour())?; datetime::encode_decimal(encoder, Self::TAG, self.0.minutes())?; datetime::encode_decimal(encoder, Self::TAG, self.0.seconds())?; - encoder.byte(b'Z') + encoder.write_byte(b'Z') } } diff --git a/der/src/byte_slice.rs b/der/src/byte_slice.rs index 18f341aef..1dce4ef2d 100644 --- a/der/src/byte_slice.rs +++ b/der/src/byte_slice.rs @@ -3,7 +3,7 @@ use crate::{ str_slice::StrSlice, DecodeValue, Decoder, DerOrd, EncodeValue, Encoder, Error, Header, Length, - Result, + Result, Writer, }; use core::cmp::Ordering; @@ -67,7 +67,7 @@ impl EncodeValue for ByteSlice<'_> { } fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.bytes(self.as_ref()) + encoder.write(self.as_ref()) } } diff --git a/der/src/datetime.rs b/der/src/datetime.rs index 6aba89c21..2c2b2549b 100644 --- a/der/src/datetime.rs +++ b/der/src/datetime.rs @@ -5,7 +5,7 @@ // Copyright (c) 2016 The humantime Developers // Released under the MIT OR Apache 2.0 licenses -use crate::{Encoder, Error, ErrorKind, Result, Tag}; +use crate::{Encoder, Error, ErrorKind, Result, Tag, Writer}; use core::{fmt, str::FromStr, time::Duration}; #[cfg(feature = "std")] @@ -372,8 +372,6 @@ pub(crate) fn decode_decimal(tag: Tag, hi: u8, lo: u8) -> Result { } /// Encode 2-digit decimal value -// TODO(tarcieri): checked arithmetic -#[allow(clippy::integer_arithmetic)] pub(crate) fn encode_decimal(encoder: &mut Encoder<'_>, tag: Tag, value: u8) -> Result<()> { let hi_val = value / 10; @@ -381,8 +379,8 @@ pub(crate) fn encode_decimal(encoder: &mut Encoder<'_>, tag: Tag, value: u8) -> return Err(tag.value_error()); } - encoder.byte(hi_val + b'0')?; - encoder.byte((value % 10) + b'0') + encoder.write_byte(b'0'.checked_add(hi_val).ok_or(ErrorKind::Overflow)?)?; + encoder.write_byte(b'0'.checked_add(value % 10).ok_or(ErrorKind::Overflow)?) } #[cfg(test)] diff --git a/der/src/document.rs b/der/src/document.rs index 5cf91a94b..90206d1e0 100644 --- a/der/src/document.rs +++ b/der/src/document.rs @@ -1,6 +1,6 @@ //! ASN.1 DER-encoded documents stored on the heap. -use crate::{Decode, Decoder, Encode, Encoder, Error, FixedTag, Length, Result, Tag}; +use crate::{Decode, Decoder, Encode, Encoder, Error, FixedTag, Length, Result, Tag, Writer}; use alloc::vec::Vec; use core::fmt::{self, Debug}; @@ -166,7 +166,7 @@ impl Encode for Document { } fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.bytes(self.as_bytes()) + encoder.write(self.as_bytes()) } } diff --git a/der/src/encoder.rs b/der/src/encoder.rs index b3a47388b..5cdb49d28 100644 --- a/der/src/encoder.rs +++ b/der/src/encoder.rs @@ -2,7 +2,7 @@ use crate::{ asn1::*, Encode, EncodeRef, EncodeValue, Error, ErrorKind, Header, Length, Result, Tag, - TagMode, TagNumber, Tagged, + TagMode, TagNumber, Tagged, Writer, }; /// DER encoder. @@ -213,23 +213,6 @@ impl<'a> Encoder<'a> { Ok(slice) } - /// Encode a single byte into the backing buffer. - pub(crate) fn byte(&mut self, byte: u8) -> Result<()> { - match self.reserve(1u8)?.first_mut() { - Some(b) => { - *b = byte; - Ok(()) - } - None => self.error(ErrorKind::Overlength), - } - } - - /// Encode the provided byte slice into the backing buffer. - pub(crate) fn bytes(&mut self, slice: &[u8]) -> Result<()> { - self.reserve(slice.len())?.copy_from_slice(slice); - Ok(()) - } - /// Get the size of the buffer in bytes. fn buffer_len(&self) -> Result { self.bytes @@ -250,6 +233,13 @@ impl<'a> Encoder<'a> { } } +impl<'a> Writer for Encoder<'a> { + fn write(&mut self, slice: &[u8]) -> Result<()> { + self.reserve(slice.len())?.copy_from_slice(slice); + Ok(()) + } +} + #[cfg(test)] mod tests { use hex_literal::hex; diff --git a/der/src/length.rs b/der/src/length.rs index 953bd1209..da83ca45b 100644 --- a/der/src/length.rs +++ b/der/src/length.rs @@ -1,6 +1,6 @@ //! Length calculations for encoded ASN.1 DER values -use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Result}; +use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Result, Writer}; use core::{ cmp::Ordering, fmt, @@ -241,17 +241,17 @@ impl Encode for Length { #[allow(clippy::cast_possible_truncation)] fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> { if let Some(tag_byte) = self.initial_octet() { - encoder.byte(tag_byte)?; + encoder.write_byte(tag_byte)?; // Strip leading zeroes match self.0.to_be_bytes() { - [0, 0, 0, byte] => encoder.byte(byte), - [0, 0, bytes @ ..] => encoder.bytes(&bytes), - [0, bytes @ ..] => encoder.bytes(&bytes), - bytes => encoder.bytes(&bytes), + [0, 0, 0, byte] => encoder.write_byte(byte), + [0, 0, bytes @ ..] => encoder.write(&bytes), + [0, bytes @ ..] => encoder.write(&bytes), + bytes => encoder.write(&bytes), } } else { - encoder.byte(self.0 as u8) + encoder.write_byte(self.0 as u8) } } } diff --git a/der/src/lib.rs b/der/src/lib.rs index 3a727568f..139306ff2 100644 --- a/der/src/lib.rs +++ b/der/src/lib.rs @@ -359,6 +359,7 @@ mod length; mod ord; mod str_slice; mod tag; +mod writer; #[cfg(feature = "alloc")] mod document; @@ -376,6 +377,7 @@ pub use crate::{ length::Length, ord::{DerOrd, ValueOrd}, tag::{Class, FixedTag, Tag, TagMode, TagNumber, Tagged}, + writer::Writer, }; #[cfg(feature = "alloc")] diff --git a/der/src/str_slice.rs b/der/src/str_slice.rs index b060e2385..fe063cbc0 100644 --- a/der/src/str_slice.rs +++ b/der/src/str_slice.rs @@ -1,7 +1,9 @@ //! Common handling for types backed by `str` slices with enforcement of a //! library-level length limitation i.e. `Length::max()`. -use crate::{ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Header, Length, Result}; +use crate::{ + ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Header, Length, Result, Writer, +}; use core::str; /// String slice newtype which respects the [`Length::max`] limit. @@ -74,6 +76,6 @@ impl<'a> EncodeValue for StrSlice<'a> { } fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.bytes(self.as_ref()) + encoder.write(self.as_ref()) } } diff --git a/der/src/tag.rs b/der/src/tag.rs index 3aa102c60..65943d3dc 100644 --- a/der/src/tag.rs +++ b/der/src/tag.rs @@ -6,7 +6,7 @@ mod number; pub use self::{class::Class, mode::TagMode, number::TagNumber}; -use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Length, Result}; +use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Length, Result, Writer}; use core::{cmp::Ordering, fmt}; /// Indicator bit for constructed form encoding (i.e. vs primitive form) @@ -314,7 +314,7 @@ impl Encode for Tag { } fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> { - encoder.byte(self.into()) + encoder.write_byte(self.into()) } } diff --git a/der/src/writer.rs b/der/src/writer.rs new file mode 100644 index 000000000..de2e35349 --- /dev/null +++ b/der/src/writer.rs @@ -0,0 +1,14 @@ +//! Writer trait. + +use crate::Result; + +/// Writer trait which outputs encoded DER. +pub trait Writer: Sized { + /// Write the given DER-encoded bytes as output. + fn write(&mut self, slice: &[u8]) -> Result<()>; + + /// Write a single byte. + fn write_byte(&mut self, byte: u8) -> Result<()> { + self.write(&[byte]) + } +}