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
34 changes: 27 additions & 7 deletions der/derive/src/enumerated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::ATTR_NAME;
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::quote;
use syn::{DeriveInput, Expr, ExprLit, Ident, Lit, LitInt, Variant};
use syn::{DeriveInput, Expr, ExprLit, Ident, Lit, LitInt, Meta, MetaList, NestedMeta, Variant};

/// Valid options for the `#[repr]` attribute on `Enumerated` types.
const REPR_TYPES: &[&str] = &["u8", "u16", "u32"];
Expand All @@ -19,6 +19,9 @@ pub(crate) struct DeriveEnumerated {
/// Value of the `repr` attribute.
repr: Ident,

/// Whether or not to tag the enum as an integer
integer: bool,

Comment on lines +22 to +24
Copy link
Member

Choose a reason for hiding this comment

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

This seems like an inextensible way to override the tag of an Enumerated, so why not just add a #[asn1(tag = "...")] argument instead that lets you override the ENUMERATED tag however you want? Then it could potentially work for more than just INTEGER.

/// Variants of this enum.
variants: Vec<EnumeratedVariant>,
}
Expand All @@ -36,13 +39,25 @@ impl DeriveEnumerated {

// Reject `asn1` attributes, parse the `repr` attribute
let mut repr: Option<Ident> = None;
let mut integer = false;

for attr in &input.attrs {
if attr.path.is_ident(ATTR_NAME) {
abort!(
attr.path,
"`asn1` attribute is not allowed on `Enumerated` types"
);
if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() {
for meta in nested {
if let NestedMeta::Meta(Meta::NameValue(nv)) = meta {
if nv.path.is_ident("type") {
if let Lit::Str(lit) = nv.lit {
match lit.value().as_str() {
"ENUMERATED" => integer = false,
"INTEGER" => integer = true,
s => abort!(lit, "`type = \"{}\"` is unsupported", s),
}
}
}
}
}
}
Comment on lines +46 to +60
Copy link
Member

Choose a reason for hiding this comment

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

This is... less than ideal, but I have some ideas about how to refactor this along with attribute parsing in general which I can do in a followup PR.

} else if attr.path.is_ident("repr") {
if repr.is_some() {
abort!(
Expand Down Expand Up @@ -81,13 +96,18 @@ impl DeriveEnumerated {
)
}),
variants,
integer,
}
}

/// Lower the derived output into a [`TokenStream`].
pub fn to_tokens(&self) -> TokenStream {
let ident = &self.ident;
let repr = &self.repr;
let tag = match self.integer {
false => quote! { ::der::Tag::Enumerated },
true => quote! { ::der::Tag::Integer },
};

let mut try_from_body = Vec::new();
for variant in &self.variants {
Expand Down Expand Up @@ -115,7 +135,7 @@ impl DeriveEnumerated {
}

impl ::der::FixedTag for #ident {
const TAG: ::der::Tag = ::der::Tag::Enumerated;
const TAG: ::der::Tag = #tag;
}

impl TryFrom<#repr> for #ident {
Expand All @@ -124,7 +144,7 @@ impl DeriveEnumerated {
fn try_from(n: #repr) -> ::der::Result<Self> {
match n {
#(#try_from_body)*
_ => Err(der::Tag::Enumerated.value_error())
_ => Err(#tag.value_error())
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion der/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ pub fn derive_choice(input: TokenStream) -> TokenStream {
///
/// Note that the derive macro will write a `TryFrom<...>` impl for the
/// provided `#[repr]`, which is used by the decoder.
#[proc_macro_derive(Enumerated)]
#[proc_macro_derive(Enumerated, attributes(asn1))]
#[proc_macro_error]
pub fn derive_enumerated(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand Down
43 changes: 4 additions & 39 deletions pkcs10/src/version.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,14 @@
//! Certification request information version identifier.

use der::{Decodable, Decoder, Encodable, Encoder, FixedTag, Tag};
use der::Enumerated;

/// Version identifier for certification request information.
///
/// (RFC 2986 designates `0` as the only valid version)
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)]
#[asn1(type = "INTEGER")]
#[repr(u8)]
pub enum Version {
/// Denotes PKCS#8 v1
V1 = 0,
}

impl Decodable<'_> for Version {
fn decode(decoder: &mut Decoder<'_>) -> der::Result<Self> {
Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error())
}
}

impl Encodable for Version {
fn encoded_len(&self) -> der::Result<der::Length> {
der::Length::from(1u8).for_tlv()
}

fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
u8::from(*self).encode(encoder)
}
}

impl From<Version> for u8 {
fn from(version: Version) -> Self {
version as u8
}
}

impl TryFrom<u8> for Version {
type Error = der::Error;

fn try_from(byte: u8) -> Result<Version, der::Error> {
match byte {
0 => Ok(Version::V1),
_ => Err(Self::TAG.value_error()),
}
}
}

impl FixedTag for Version {
const TAG: Tag = Tag::Integer;
}
31 changes: 27 additions & 4 deletions x509/src/certificate.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
//! Certificate [`Certificate`] and TBSCertificate [`TBSCertificate`] as defined in RFC 5280

use der::asn1::{BitString, ContextSpecific, ObjectIdentifier, UIntBytes};
use der::{Sequence, TagMode, TagNumber};
use der::{Enumerated, Sequence, TagMode, TagNumber};
use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
use x501::name::Name;
use x501::time::Validity;

/// only support v3 certificates
/// Certificate `Version` as defined in [RFC 5280 Section 4.1].
///
/// ```text
/// Version ::= INTEGER { v1(0), v2(1), v3(2) }
pub const X509_CERT_VERSION: u8 = 2;
/// ```
///
/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)]
#[asn1(type = "INTEGER")]
#[repr(u8)]
pub enum Version {
/// Version 1 (default)
V1 = 0,

/// Version 2
V2 = 1,

/// Version 3
V3 = 2,
}

impl Default for Version {
fn default() -> Self {
Self::V1
}
}

/// X.509 `TBSCertificate` as defined in [RFC 5280 Section 4.1.2.5]
///
Expand Down Expand Up @@ -39,7 +62,7 @@ pub const X509_CERT_VERSION: u8 = 2;
pub struct TBSCertificate<'a> {
/// version [0] Version DEFAULT v1,
//#[asn1(context_specific = "0", default = "Default::default")]
pub version: u8,
pub version: Version,
/// serialNumber CertificateSerialNumber,
pub serial_number: UIntBytes<'a>,
/// signature AlgorithmIdentifier{SIGNATURE-ALGORITHM, {SignatureAlgorithms}},
Expand Down
2 changes: 1 addition & 1 deletion x509/tests/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ fn decode_cert() {
let result = Certificate::from_der(der_encoded_cert);
let cert: Certificate = result.unwrap();

assert_eq!(cert.tbs_certificate.version, 2);
assert_eq!(cert.tbs_certificate.version, Version::V3);
let target_serial: [u8; 16] = [
0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x49, 0xCF, 0x70, 0x66, 0x4D, 0x00, 0x00, 0x00,
0x02,
Expand Down
2 changes: 1 addition & 1 deletion x509/tests/pkix_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ fn decode_cert() {
let result = Certificate::from_der(der_encoded_cert);
let cert: Certificate = result.unwrap();

assert_eq!(cert.tbs_certificate.version, 2);
assert_eq!(cert.tbs_certificate.version, Version::V3);
let target_serial: [u8; 1] = [2];
assert_eq!(
cert.tbs_certificate.serial_number,
Expand Down