Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions der/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,24 @@ mod utc_time;
mod utf8_string;
mod videotex_string;

#[cfg(feature = "oid")]
#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
pub use const_oid::ObjectIdentifier;

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub use self::{
any::Any, bit_string::BitString, integer::bigint::Uint, octet_string::OctetString,
set_of::SetOfVec,
};
pub use self::{
any::AnyRef,
bit_string::{BitStringIter, BitStringRef},
choice::Choice,
context_specific::{ContextSpecific, ContextSpecificRef},
generalized_time::GeneralizedTime,
ia5_string::Ia5StringRef,
integer::bigint::IntRef,
integer::bigint::UintRef,
null::Null,
octet_string::OctetStringRef,
Expand All @@ -44,14 +55,3 @@ pub use self::{
utf8_string::Utf8StringRef,
videotex_string::VideotexStringRef,
};

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub use self::{
any::Any, bit_string::BitString, integer::bigint::Uint, octet_string::OctetString,
set_of::SetOfVec,
};

#[cfg(feature = "oid")]
#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
pub use const_oid::ObjectIdentifier;
3 changes: 2 additions & 1 deletion der/src/asn1/integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ pub(super) mod bigint;
pub(super) mod int;
pub(super) mod uint;

use core::{cmp::Ordering, mem};

use crate::{
asn1::AnyRef, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader,
Result, SliceWriter, Tag, ValueOrd, Writer,
};
use core::{cmp::Ordering, mem};

macro_rules! impl_int_encoding {
($($int:ty => $uint:ty),+) => {
Expand Down
191 changes: 188 additions & 3 deletions der/src/asn1/integer/bigint.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,94 @@
//! "Big" ASN.1 `INTEGER` types.

use super::uint;
use super::{int, uint};
use crate::{
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind,
FixedTag, Header, Length, Reader, Result, Tag, Writer,
};

/// "Big" signed ASN.1 `INTEGER` type.
///
/// Provides direct access to the underlying big endian bytes which comprise
/// an signed integer value.
///
/// Intended for use cases like very large integers that are used in
/// cryptographic applications (e.g. keys, signatures).
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct IntRef<'a> {
/// Inner value
inner: ByteSlice<'a>,
}

impl<'a> IntRef<'a> {
/// Create a new [`IntRef`] from a byte slice.
pub fn new(bytes: &'a [u8]) -> Result<Self> {
let inner = ByteSlice::new(int::strip_leading_ones(bytes))
.map_err(|_| ErrorKind::Length { tag: Self::TAG })?;

Ok(Self { inner })
}

/// Borrow the inner byte slice which contains the least significant bytes
/// of a big endian integer value with all leading ones stripped.
pub fn as_bytes(&self) -> &'a [u8] {
self.inner.as_slice()
}

/// Get the length of this [`IntRef`] in bytes.
pub fn len(&self) -> Length {
self.inner.len()
}

/// Is the inner byte slice empty?
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}

impl<'a> DecodeValue<'a> for IntRef<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
let bytes = ByteSlice::decode_value(reader, header)?.as_slice();
let result = Self::new(int::decode_to_slice(bytes)?)?;

// Ensure we compute the same encoded length as the original any value.
if result.value_len()? != header.length {
return Err(Self::TAG.non_canonical_error());
}

Ok(result)
}
}

impl<'a> EncodeValue for IntRef<'a> {
fn value_len(&self) -> Result<Length> {
int::encoded_len(self.inner.as_slice())
}

fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
writer.write(self.as_bytes())
}
}

impl<'a> From<&IntRef<'a>> for IntRef<'a> {
fn from(value: &IntRef<'a>) -> IntRef<'a> {
*value
}
}

impl<'a> TryFrom<AnyRef<'a>> for IntRef<'a> {
type Error = Error;

fn try_from(any: AnyRef<'a>) -> Result<IntRef<'a>> {
any.decode_into()
}
}

impl<'a> FixedTag for IntRef<'a> {
const TAG: Tag = Tag::Integer;
}

impl<'a> OrdIsValueOrd for IntRef<'a> {}

/// "Big" unsigned ASN.1 `INTEGER` type.
///
/// Provides direct access to the underlying big endian bytes which comprise an
Expand Down Expand Up @@ -95,11 +178,11 @@ impl<'a> FixedTag for UintRef<'a> {
impl<'a> OrdIsValueOrd for UintRef<'a> {}

#[cfg(feature = "alloc")]
pub use self::allocating::Uint;
pub use self::allocating::{Int, Uint};

#[cfg(feature = "alloc")]
mod allocating {
use super::{super::uint, UintRef};
use super::{super::int, super::uint, IntRef, UintRef};
use crate::{
asn1::AnyRef,
ord::OrdIsValueOrd,
Expand All @@ -108,6 +191,108 @@ mod allocating {
Result, Tag, Writer,
};

/// "Big" signed ASN.1 `INTEGER` type.
///
/// Provides direct storage for the big endian bytes which comprise an
/// signed integer value.
///
/// Intended for use cases like very large integers that are used in
/// cryptographic applications (e.g. keys, signatures).
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Int {
/// Inner value
inner: Bytes,
}

impl Int {
/// Create a new [`Int`] from a byte slice.
pub fn new(bytes: &[u8]) -> Result<Self> {
let inner = Bytes::new(int::strip_leading_ones(bytes))
.map_err(|_| ErrorKind::Length { tag: Self::TAG })?;

Ok(Self { inner })
}

/// Borrow the inner byte slice which contains the least significant bytes
/// of a big endian integer value with all leading ones stripped.
pub fn as_bytes(&self) -> &[u8] {
self.inner.as_slice()
}

/// Get the length of this [`Int`] in bytes.
pub fn len(&self) -> Length {
self.inner.len()
}

/// Is the inner byte slice empty?
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}

impl<'a> DecodeValue<'a> for Int {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
let bytes = Bytes::decode_value(reader, header)?;
let result = Self::new(int::decode_to_slice(bytes.as_slice())?)?;

// Ensure we compute the same encoded length as the original any value.
if result.value_len()? != header.length {
return Err(Self::TAG.non_canonical_error());
}

Ok(result)
}
}

impl EncodeValue for Int {
fn value_len(&self) -> Result<Length> {
int::encoded_len(self.inner.as_slice())
}

fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
writer.write(self.as_bytes())
}
}

impl<'a> From<&IntRef<'a>> for Int {
fn from(value: &IntRef<'a>) -> Int {
let inner = Bytes::new(value.as_bytes()).expect("Invalid Int");
Int { inner }
}
}

impl<'a> TryFrom<AnyRef<'a>> for Int {
type Error = Error;

fn try_from(any: AnyRef<'a>) -> Result<Int> {
any.decode_into()
}
}

impl FixedTag for Int {
const TAG: Tag = Tag::Integer;
}

impl OrdIsValueOrd for Int {}

impl<'a> RefToOwned<'a> for IntRef<'a> {
type Owned = Int;
fn to_owned(&self) -> Self::Owned {
let inner = self.inner.to_owned();

Int { inner }
}
}

impl OwnedToRef for Int {
type Borrowed<'a> = IntRef<'a>;
fn to_ref(&self) -> Self::Borrowed<'_> {
let inner = self.inner.to_ref();

IntRef { inner }
}
}

/// "Big" unsigned ASN.1 `INTEGER` type.
///
/// Provides direct storage for the big endian bytes which comprise an
Expand Down
20 changes: 16 additions & 4 deletions der/src/asn1/integer/int.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
//! Support for encoding negative integers

use super::is_highest_bit_set;
use crate::{ErrorKind, Length, Result, Writer};
use crate::{ErrorKind, Length, Result, Tag, Writer};

/// Decode an unsigned integer of the specified size.
pub(super) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> {
// The `INTEGER` type always encodes a signed value, so for unsigned
// values the leading `0x00` byte may need to be removed.
match bytes {
[] => Err(Tag::Integer.non_canonical_error()),
[0] => Ok(bytes),
[0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()),
[0, rest @ ..] => Ok(rest),
_ => Ok(bytes),
}
}

/// Decode an signed integer of the specified size.
///
/// Returns a byte array of the requested size containing a big endian integer.
pub(super) fn decode_to_array<const N: usize>(bytes: &[u8]) -> Result<[u8; N]> {
Expand Down Expand Up @@ -34,14 +46,14 @@ where
writer.write(strip_leading_ones(bytes))
}

/// Get the encoded length for the given unsigned integer serialized as bytes.
/// Get the encoded length for the given signed integer serialized as bytes.
#[inline]
pub(super) fn encoded_len(bytes: &[u8]) -> Result<Length> {
Length::try_from(strip_leading_ones(bytes).len())
}

/// Strip the leading all-ones bytes from the given byte slice.
fn strip_leading_ones(mut bytes: &[u8]) -> &[u8] {
pub(crate) fn strip_leading_ones(mut bytes: &[u8]) -> &[u8] {
Comment on lines -37 to +56
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

N.B.: I updated these comments; based on the context and behavior it looks like they were incorrectly copy-pasted before.

while let Some((byte, rest)) = bytes.split_first() {
if *byte == 0xFF && is_highest_bit_set(rest) {
bytes = rest;
Expand Down