Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 0 additions & 4 deletions der/derive/src/choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,6 @@ impl DeriveChoice {
/// ASN.1 `CHOICE` alternative: one of the ASN.1 types comprising the `CHOICE`
/// which maps to an enum variant.
struct Alternative {
/// ASN.1 type for this alternative.
pub asn1_type: Asn1Type,

/// [`Ident`] for the corresponding enum variant.
pub ident: Ident,

Expand All @@ -246,7 +243,6 @@ impl Alternative {
};

let alternative = Self {
asn1_type,
ident: variant.ident.clone(),
field_type,
};
Expand Down
77 changes: 21 additions & 56 deletions der/src/asn1/context_specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,32 @@

use crate::{
Any, Choice, Decodable, Encodable, Encoder, Error, ErrorKind, Header, Length, Result, Tag,
TagNumber,
};
use core::convert::TryFrom;

/// Context-specific field.
///
/// This type encodes a field which is specific to a particular context,
/// and has a special "context-specific tag" (presently 0-15 supported).
/// and is identified by a [`TagNumber`].
///
/// Any context-specific field can be decoded/encoded with this type.
/// The intended use is to dynamically dispatch off of the context-specific
/// tag when decoding, which allows support for extensions, which are denoted
/// in an ASN.1 schema using the `...` ellipsis extension marker.
///
///
/// tag number when decoding, which allows support for extensions, which are
/// denoted in an ASN.1 schema using the `...` ellipsis extension marker.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct ContextSpecific<'a> {
/// Context-specific tag value sans the leading `0b10000000` class
/// Context-specific tag number sans the leading `0b10000000` class
/// identifier bit and `0b100000` constructed flag.
pub(crate) tag: u8,
pub tag_number: TagNumber,

/// Value of the field.
pub(crate) value: Any<'a>,
}

impl<'a> ContextSpecific<'a> {
/// Create a new context-specific field.
///
/// The tag value includes only lower 6-bits of the context specific tag,
/// sans the leading `10` high bits identifying the context-specific tag
/// class as well as the constructed flag.
pub fn new(tag: u8, value: Any<'a>) -> Result<Self> {
// Ensure we consider the context-specific tag valid
Tag::context_specific(tag)?;

Ok(Self { tag, value })
}

/// Get the context-specific tag for this field.
///
/// The tag value includes only lower 6-bits of the context specific tag,
/// sans the leading `10` high bits identifying the context-specific tag
/// class as well as the constructed flag.
pub fn tag(self) -> u8 {
self.tag
}

/// Get the value of this context-specific tag.
pub fn value(self) -> Any<'a> {
self.value
}
pub value: Any<'a>,
}

impl<'a> Choice<'a> for ContextSpecific<'a> {
fn can_decode(tag: Tag) -> bool {
tag.is_context_specific()
matches!(tag, Tag::ContextSpecific(_))
}
}

Expand All @@ -66,7 +37,7 @@ impl<'a> Encodable for ContextSpecific<'a> {
}

fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
let tag = Tag::context_specific(self.tag)?;
let tag = Tag::ContextSpecific(self.tag_number);
Header::new(tag, self.value.encoded_len()?)?.encode(encoder)?;
self.value.encode(encoder)
}
Expand All @@ -82,21 +53,17 @@ impl<'a> TryFrom<Any<'a>> for ContextSpecific<'a> {
type Error = Error;

fn try_from(any: Any<'a>) -> Result<ContextSpecific<'a>> {
let tag = if any.tag().is_context_specific() {
(any.tag() as u8)
.checked_sub(0xA0)
.ok_or(ErrorKind::Overflow)?
} else {
return Err(ErrorKind::UnexpectedTag {
match any.tag() {
Tag::ContextSpecific(tag_number) => Ok(Self {
tag_number,
value: Any::from_der(any.as_bytes())?,
}),
actual => Err(ErrorKind::UnexpectedTag {
expected: None,
actual: any.tag(),
actual,
}
.into());
};

let value = Any::from_der(any.as_bytes())?;

Self::new(tag, value)
.into()),
}
}
}

Expand All @@ -113,11 +80,9 @@ mod tests {
#[test]
fn round_trip() {
let field = ContextSpecific::from_der(EXAMPLE_BYTES).unwrap();
assert_eq!(field.tag(), 1);

let value = field.value();
assert_eq!(value.tag(), Tag::BitString);
assert_eq!(value.as_bytes(), &EXAMPLE_BYTES[5..]);
assert_eq!(field.tag_number.value(), 1);
assert_eq!(field.value.tag(), Tag::BitString);
assert_eq!(field.value.as_bytes(), &EXAMPLE_BYTES[5..]);

let mut buf = [0u8; 128];
let encoded = field.encode_to_slice(&mut buf).unwrap();
Expand Down
6 changes: 4 additions & 2 deletions der/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
//!
//! This crate provides a `no_std`-friendly implementation of a subset of ASN.1
//! DER necessary for decoding/encoding various cryptography-related formats
//! implemented as part of the [RustCrypto] project, e.g. the [`pkcs8`] crate.
//! implemented as part of the [RustCrypto] project, e.g. the [`pkcs5`] and
//! [`pkcs8`] crates.
//!
//! The core implementation avoids any heap usage (with convenience methods
//! that allocate gated under the off-by-default `alloc` feature).
Expand Down Expand Up @@ -315,6 +316,7 @@
//!
//! [X.690]: https://www.itu.int/rec/T-REC-X.690/
//! [RustCrypto]: https://github.com/rustcrypto
//! [`pkcs5`]: https://docs.rs/pkcs5/
//! [`pkcs8`]: https://docs.rs/pkcs8/
//! [RustCrypto/utils#370]: https://github.com/RustCrypto/utils/issues/370
//! [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2
Expand Down Expand Up @@ -376,7 +378,7 @@ pub use crate::{
header::Header,
length::Length,
message::Message,
tag::{Class, Tag, Tagged},
tag::{Class, Tag, TagNumber, Tagged},
};

pub(crate) use crate::byte_slice::ByteSlice;
Expand Down
Loading