Skip to content

Commit cfacd3e

Browse files
authored
x509-cert: impl DecodeValue for Time (#1986)
* x509-cert: impl `DecodeValue` for `Time` To deserialize SigningTime attributes from CMS, Time needs implement DecodeValue.a ``` -- rfc3852 Attribute ::= SEQUENCE { attrType OBJECT IDENTIFIER, attrValues SET OF AttributeValue } AttributeValue ::= ANY -- rfc5911 SigningTime ::= Time Time ::= CHOICE { utcTime UTCTime, generalTime GeneralizedTime } aa-signingTime ATTRIBUTE ::= { TYPE SigningTime IDENTIFIED BY id-signingTime } id-signingTime OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) 5 } ``` This adds the missing implementation. * der_derive: impl DecodeValue for Choice
1 parent b52bdaf commit cfacd3e

File tree

6 files changed

+105
-25
lines changed

6 files changed

+105
-25
lines changed

cms/tests/signed_data.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22
33
use cms::content_info::ContentInfo;
44
use cms::signed_data::{SignedData, SignerInfos};
5-
use der::{AnyRef, Decode, DecodePem, Encode, ErrorKind, Tag};
6-
use x509_cert::Certificate;
5+
use const_oid::db::rfc5911;
6+
use core::str::FromStr;
7+
use der::{AnyRef, DateTime, Decode, DecodePem, Encode, ErrorKind, Tag, asn1::SetOfVec};
8+
use x509_cert::{
9+
Certificate,
10+
attr::{Attribute, AttributeValue},
11+
time::Time,
12+
};
713

814
#[test]
915
fn trust_list_sd_test() {
@@ -143,3 +149,23 @@ fn certs_to_p7b() {
143149
let p7b_buf2 = p7b_ee.to_der().unwrap();
144150
assert_eq!(p7b_buf, p7b_buf2.as_slice());
145151
}
152+
153+
#[test]
154+
fn encode_decode_signing_time() {
155+
let time = DateTime::from_str("2024-12-31T23:59:59Z").unwrap();
156+
157+
// First serialize the attribute
158+
let time = Time::from(time);
159+
let time_der = time.to_der().unwrap();
160+
let signing_time_attribute_value = AttributeValue::from_der(&time_der).unwrap();
161+
let mut values = SetOfVec::<AttributeValue>::new();
162+
values.insert(signing_time_attribute_value.clone()).unwrap();
163+
let _attribute = Attribute {
164+
oid: rfc5911::ID_SIGNING_TIME,
165+
values,
166+
};
167+
168+
// and deserialize
169+
let time_deserialized = signing_time_attribute_value.decode_as::<Time>().unwrap();
170+
assert_eq!(time, time_deserialized);
171+
}

der_derive/src/asn1_type.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,25 @@ impl Asn1Type {
6161
let type_path = self.type_path();
6262
quote!(#type_path::decode(reader)?)
6363
}
64+
6465
/// Get a `der::Decoder` optional object for a particular ASN.1 type
6566
pub fn decoder_optional(self) -> TokenStream {
6667
let type_path = self.type_path();
6768
quote!(Option::<#type_path>::decode(reader)?)
6869
}
6970

71+
/// Get a `der::DecodeValue` member object for a particular ASN.1 type
72+
pub fn value_decoder(self) -> TokenStream {
73+
let type_path = self.type_path();
74+
quote!(#type_path::decode_value(reader, header)?)
75+
}
76+
77+
/// Get a `der::DecodeValue` member object for a particular ASN.1 type
78+
pub fn value_decoder_optional(self) -> TokenStream {
79+
let type_path = self.type_path();
80+
quote!(Option::<#type_path>::decode_value(reader, header)?)
81+
}
82+
7083
/// Get a `der::Encoder` object for a particular ASN.1 type
7184
pub fn encoder(self, binding: &TokenStream) -> TokenStream {
7285
let type_path = self.type_path();

der_derive/src/attributes.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,26 @@ impl FieldAttrs {
296296
}
297297
}
298298

299+
/// Get a `der::DecodeValue` member which respects these field attributes.
300+
pub fn value_decoder(&self) -> TokenStream {
301+
if let Some(default) = &self.default {
302+
let type_params = self.asn1_type.map(|ty| ty.type_path()).unwrap_or_default();
303+
self.asn1_type.map(|ty| ty.value_decoder()).unwrap_or_else(|| {
304+
quote! {
305+
Option::<#type_params>::decode_value(reader, header)?.unwrap_or_else(#default),
306+
}
307+
})
308+
} else if self.is_optional() {
309+
self.asn1_type
310+
.map(|ty| ty.value_decoder_optional())
311+
.unwrap_or_else(|| quote!(<_>::decode_value(reader, header)?))
312+
} else {
313+
self.asn1_type
314+
.map(|ty| ty.value_decoder())
315+
.unwrap_or_else(|| quote!(<_>::decode_value(reader, header)?))
316+
}
317+
}
318+
299319
pub fn custom_class_decoder(&self, class_num: &ClassNum) -> TokenStream {
300320
let type_params = self.asn1_type.map(|ty| ty.type_path()).unwrap_or(quote!(_));
301321
let ClassTokens {

der_derive/src/choice.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ impl DeriveChoice {
7676

7777
let mut can_decode_body = Vec::new();
7878
let mut decode_body = Vec::new();
79+
let mut decode_value_body = Vec::new();
7980
let mut encode_body = Vec::new();
8081
let mut value_len_body = Vec::new();
8182
let mut tagged_body = Vec::new();
8283

8384
for variant in &self.variants {
8485
can_decode_body.push(variant.tag.to_tokens());
8586
decode_body.push(variant.to_decode_tokens());
87+
decode_value_body.push(variant.to_decode_value_tokens());
8688
encode_body.push(variant.to_encode_value_tokens());
8789
value_len_body.push(variant.to_value_len_tokens());
8890
tagged_body.push(variant.to_tagged_tokens());
@@ -120,6 +122,24 @@ impl DeriveChoice {
120122
}
121123
}
122124

125+
impl #impl_generics ::der::DecodeValue<#lifetime> for #ident #ty_generics #where_clause {
126+
type Error = #error;
127+
128+
fn decode_value<R: ::der::Reader<#lifetime>>(reader: &mut R, header: der::Header) -> ::core::result::Result<Self, #error> {
129+
match header.tag() {
130+
#(#decode_value_body)*
131+
actual => Err(::der::Error::new(
132+
::der::ErrorKind::TagUnexpected {
133+
expected: None,
134+
actual
135+
},
136+
reader.position()
137+
).into()
138+
),
139+
}
140+
}
141+
}
142+
123143
impl #impl_generics ::der::EncodeValue for #ident #ty_generics #where_clause {
124144
fn encode_value(&self, encoder: &mut impl ::der::Writer) -> ::der::Result<()> {
125145
match self {

der_derive/src/choice/variant.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl ChoiceVariant {
9797
Ok(Self { ident, attrs, tag })
9898
}
9999

100-
/// Derive a match arm of the impl body for `TryFrom<der::asn1::Any<'_>>`.
100+
/// Derive a match arm of the impl body for `der::Decode<'_>`.
101101
pub(super) fn to_decode_tokens(&self) -> TokenStream {
102102
let tag = self.tag.to_tokens();
103103
let ident = &self.ident;
@@ -109,6 +109,18 @@ impl ChoiceVariant {
109109
}
110110
}
111111

112+
/// Derive a match arm of the impl body for `der::DecodeValue<'_>`.
113+
pub(super) fn to_decode_value_tokens(&self) -> TokenStream {
114+
let tag = self.tag.to_tokens();
115+
let ident = &self.ident;
116+
let decoder = self.attrs.value_decoder();
117+
118+
match self.attrs.asn1_type {
119+
Some(..) => quote! { #tag => Ok(Self::#ident(#decoder.try_into()?)), },
120+
None => quote! { #tag => Ok(Self::#ident(#decoder)), },
121+
}
122+
}
123+
112124
/// Derive a match arm for the impl body for `der::EncodeValue::encode_value`.
113125
pub(super) fn to_encode_value_tokens(&self) -> TokenStream {
114126
let ident = &self.ident;
@@ -189,6 +201,16 @@ mod tests {
189201
.to_string()
190202
);
191203

204+
assert_eq!(
205+
variant.to_decode_value_tokens().to_string(),
206+
quote! {
207+
::der::Tag::Utf8String => Ok(Self::ExampleVariant(
208+
<_>::decode_value(reader, header)?
209+
)),
210+
}
211+
.to_string()
212+
);
213+
192214
assert_eq!(
193215
variant.to_encode_value_tokens().to_string(),
194216
quote! {

x509-cert/src/ext/pkix/name/dirstr.rs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use alloc::borrow::Cow;
22
use alloc::string::String;
33
use alloc::string::ToString;
44
use der::{
5-
Choice, FixedTag, Header, Reader, ValueOrd,
5+
Choice, ValueOrd,
66
asn1::{Any, BmpString, PrintableString, TeletexString},
77
};
88

@@ -66,27 +66,6 @@ impl<'a> TryFrom<&'a Any> for DirectoryString {
6666
}
6767
}
6868

69-
impl<'a> der::DecodeValue<'a> for DirectoryString {
70-
type Error = der::Error;
71-
72-
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
73-
match header.tag() {
74-
PrintableString::TAG => {
75-
PrintableString::decode_value(reader, header).map(Self::PrintableString)
76-
}
77-
TeletexString::TAG => {
78-
TeletexString::decode_value(reader, header).map(Self::TeletexString)
79-
}
80-
String::TAG => String::decode_value(reader, header).map(Self::Utf8String),
81-
BmpString::TAG => BmpString::decode_value(reader, header).map(Self::BmpString),
82-
actual => Err(der::ErrorKind::TagUnexpected {
83-
expected: None,
84-
actual,
85-
}
86-
.into()),
87-
}
88-
}
89-
}
9069
impl DirectoryString {
9170
/// Returns `Borrowed` variant for UTF-8 compatible strings
9271
/// and `Owned` variant otherwise.

0 commit comments

Comments
 (0)