Skip to content

Commit 82586f8

Browse files
authored
der: fix derive(Sequence) on field: Vec<u8> (#1680)
* fix: derive(Sequence) with Vec<u8> * rm comments * test(der): add regular OCTET STRING Vec<u8> * test: fix clippy
1 parent e91e337 commit 82586f8

File tree

6 files changed

+152
-16
lines changed

6 files changed

+152
-16
lines changed

der/src/asn1/bit_string.rs

+21
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,27 @@ mod allocating {
347347
}
348348
}
349349

350+
/// Hack for simplifying the custom derive use case.
351+
impl<'a> TryFrom<&'a Vec<u8>> for BitStringRef<'a> {
352+
type Error = Error;
353+
354+
fn try_from(bytes: &'a Vec<u8>) -> Result<BitStringRef<'a>> {
355+
BitStringRef::from_bytes(bytes)
356+
}
357+
}
358+
359+
/// Hack for simplifying the custom derive use case.
360+
impl<'a> TryFrom<BitStringRef<'a>> for Vec<u8> {
361+
type Error = Error;
362+
363+
fn try_from(bit_string: BitStringRef<'a>) -> Result<Vec<u8>> {
364+
bit_string
365+
.as_bytes()
366+
.map(|bytes| bytes.to_vec())
367+
.ok_or_else(|| Tag::BitString.value_error())
368+
}
369+
}
370+
350371
impl ValueOrd for BitString {
351372
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
352373
match self.unused_bits.cmp(&other.unused_bits) {

der/src/asn1/octet_string.rs

+9
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ mod allocating {
227227
}
228228
}
229229

230+
/// Hack for simplifying the custom derive use case.
231+
impl<'a> TryFrom<&'a Vec<u8>> for OctetStringRef<'a> {
232+
type Error = Error;
233+
234+
fn try_from(byte_vec: &'a Vec<u8>) -> Result<Self, Error> {
235+
OctetStringRef::new(byte_vec)
236+
}
237+
}
238+
230239
impl From<OctetString> for Vec<u8> {
231240
fn from(octet_string: OctetString) -> Vec<u8> {
232241
octet_string.into_bytes()

der/tests/derive.rs

+86
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,92 @@ mod sequence {
453453
assert_eq!(obj, obj_decoded);
454454
}
455455

456+
#[derive(Sequence, Default, Eq, PartialEq, Debug)]
457+
#[asn1(tag_mode = "IMPLICIT")]
458+
pub struct TypeCheckOwnedSequenceFieldAttributeCombinations {
459+
/// Without deref = "true" macro generates an error:
460+
///
461+
/// the trait `From<Vec<u8>>` is not implemented for `BitStringRef<'_>`
462+
#[asn1(type = "OCTET STRING", deref = "true")]
463+
pub owned_bytes: Vec<u8>,
464+
465+
#[asn1(type = "BIT STRING", deref = "true")]
466+
pub owned_bits: Vec<u8>,
467+
468+
/// pure Vec<.> Needs additional deref in the derive macro
469+
/// for the `OctetStringRef::try_from`
470+
#[asn1(type = "OCTET STRING", context_specific = "0", deref = "true")]
471+
pub owned_implicit_bytes: Vec<u8>,
472+
473+
/// deref
474+
#[asn1(type = "BIT STRING", context_specific = "1", deref = "true")]
475+
pub owned_implicit_bits: Vec<u8>,
476+
477+
/// deref
478+
#[asn1(
479+
type = "OCTET STRING",
480+
context_specific = "2",
481+
deref = "true",
482+
tag_mode = "EXPLICIT"
483+
)]
484+
pub owned_explicit_bytes: Vec<u8>,
485+
486+
/// deref
487+
#[asn1(
488+
type = "BIT STRING",
489+
context_specific = "3",
490+
deref = "true",
491+
tag_mode = "EXPLICIT"
492+
)]
493+
pub owned_explicit_bits: Vec<u8>,
494+
495+
/// Option<Vec<..>> does not need deref
496+
#[asn1(type = "BIT STRING", context_specific = "4", optional = "true")]
497+
pub owned_optional_implicit_bits: Option<Vec<u8>>,
498+
#[asn1(type = "OCTET STRING", context_specific = "5", optional = "true")]
499+
pub owned_optional_implicit_bytes: Option<Vec<u8>>,
500+
501+
#[asn1(
502+
type = "OCTET STRING",
503+
context_specific = "6",
504+
optional = "true",
505+
tag_mode = "EXPLICIT"
506+
)]
507+
pub owned_optional_explicit_bits: Option<Vec<u8>>,
508+
#[asn1(
509+
type = "OCTET STRING",
510+
context_specific = "7",
511+
optional = "true",
512+
tag_mode = "EXPLICIT"
513+
)]
514+
pub owned_optional_explicit_bytes: Option<Vec<u8>>,
515+
}
516+
517+
#[test]
518+
fn type_combinations_alloc_instance() {
519+
let obj = TypeCheckOwnedSequenceFieldAttributeCombinations {
520+
owned_bytes: vec![0xAA, 0xBB],
521+
owned_bits: vec![0xCC, 0xDD],
522+
523+
owned_implicit_bytes: vec![0, 1],
524+
owned_implicit_bits: vec![2, 3],
525+
526+
owned_explicit_bytes: vec![4, 5],
527+
owned_explicit_bits: vec![6, 7],
528+
529+
owned_optional_implicit_bits: Some(vec![8, 9]),
530+
owned_optional_implicit_bytes: Some(vec![10, 11]),
531+
532+
owned_optional_explicit_bits: Some(vec![12, 13]),
533+
owned_optional_explicit_bytes: Some(vec![14, 15]),
534+
};
535+
536+
let der_encoded = obj.to_der().unwrap();
537+
let obj_decoded =
538+
TypeCheckOwnedSequenceFieldAttributeCombinations::from_der(&der_encoded).unwrap();
539+
assert_eq!(obj, obj_decoded);
540+
}
541+
456542
#[derive(Sequence)]
457543
#[asn1(error = CustomError)]
458544
pub struct TypeWithCustomError {

der_derive/src/asn1_type.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,7 @@ impl Asn1Type {
7070
/// Get a `der::Encoder` object for a particular ASN.1 type
7171
pub fn encoder(self, binding: &TokenStream) -> TokenStream {
7272
let type_path = self.type_path();
73-
74-
match self {
75-
Asn1Type::Ia5String
76-
| Asn1Type::OctetString
77-
| Asn1Type::PrintableString
78-
| Asn1Type::TeletexString
79-
| Asn1Type::VideotexString
80-
| Asn1Type::Utf8String => quote!(#type_path::try_from(#binding)?),
81-
_ => quote!(#type_path::try_from(#binding)?),
82-
}
73+
quote!(#type_path::try_from(#binding)?)
8374
}
8475

8576
/// Get the Rust type path for a particular ASN.1 type.

der_derive/src/attributes.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,19 @@ pub(crate) struct FieldAttrs {
9191
/// Value of the `#[asn1(type = "...")]` attribute if provided.
9292
pub asn1_type: Option<Asn1Type>,
9393

94+
/// Is the inner type constructed?
95+
pub constructed: bool,
96+
9497
/// Value of the `#[asn1(context_specific = "...")] attribute if provided.
9598
pub context_specific: Option<TagNumber>,
9699

97100
/// Indicates name of function that supplies the default value, which will be used in cases
98101
/// where encoding is omitted per DER and to omit the encoding per DER
99102
pub default: Option<Path>,
100103

104+
/// Shold we add `&` before `self.field_name`?
105+
pub should_deref: bool,
106+
101107
/// Is this field "extensible", i.e. preceded by the `...` extensibility marker?
102108
pub extensible: bool,
103109

@@ -110,9 +116,6 @@ pub(crate) struct FieldAttrs {
110116
/// Inherits from the type-level tagging mode if specified, or otherwise
111117
/// defaults to `EXPLICIT`.
112118
pub tag_mode: TagMode,
113-
114-
/// Is the inner type constructed?
115-
pub constructed: bool,
116119
}
117120

118121
impl FieldAttrs {
@@ -126,12 +129,13 @@ impl FieldAttrs {
126129
/// Parse attributes from a struct field or enum variant.
127130
pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> syn::Result<Self> {
128131
let mut asn1_type = None;
132+
let mut constructed = None;
129133
let mut context_specific = None;
130134
let mut default = None;
135+
let mut should_deref = None;
131136
let mut extensible = None;
132137
let mut optional = None;
133138
let mut tag_mode = None;
134-
let mut constructed = None;
135139

136140
let mut parsed_attrs = Vec::new();
137141
AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?;
@@ -156,6 +160,12 @@ impl FieldAttrs {
156160
format_args!("error parsing ASN.1 `default` attribute: {e}"),
157161
)
158162
})?);
163+
// `deref` attribute
164+
} else if let Some(de) = attr.parse_value("deref")? {
165+
if should_deref.is_some() {
166+
abort!(attr.name, "duplicate ASN.1 `deref` attribute");
167+
}
168+
should_deref = Some(de);
159169
// `extensible` attribute
160170
} else if let Some(ext) = attr.parse_value("extensible")? {
161171
if extensible.is_some() {
@@ -195,19 +205,20 @@ impl FieldAttrs {
195205
abort!(
196206
attr.name,
197207
"unknown field-level `asn1` attribute \
198-
(valid options are `context_specific`, `type`)",
208+
(valid options are `constructed`, `context_specific`, `default`, `deref`, `extensible`, `optional`, `tag_mode`, `type`)",
199209
);
200210
}
201211
}
202212

203213
Ok(Self {
204214
asn1_type,
215+
constructed: constructed.unwrap_or_default(),
205216
context_specific,
206217
default,
218+
should_deref: should_deref.unwrap_or_default(),
207219
extensible: extensible.unwrap_or_default(),
208220
optional: optional.unwrap_or_default(),
209221
tag_mode: tag_mode.unwrap_or(type_attrs.tag_mode),
210-
constructed: constructed.unwrap_or_default(),
211222
})
212223
}
213224

der_derive/src/sequence/field.rs

+18
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ impl SequenceField {
7979
let mut lowerer = LowerFieldEncoder::new(&self.ident);
8080
let attrs = &self.attrs;
8181

82+
if self.attrs.should_deref {
83+
lowerer.apply_deref();
84+
}
85+
8286
if let Some(ty) = &attrs.asn1_type {
8387
// TODO(tarcieri): default in conjunction with ASN.1 types?
8488
debug_assert!(
@@ -188,6 +192,18 @@ impl LowerFieldEncoder {
188192
};
189193
}
190194

195+
/// Changes field access, for example from:
196+
///
197+
/// `self.field1`
198+
///
199+
/// to:
200+
///
201+
/// `&self.field1`
202+
fn apply_deref(&mut self) {
203+
let encoder = &self.encoder;
204+
self.encoder = quote!(&#encoder);
205+
}
206+
191207
/// Handle default value for a type.
192208
fn apply_default(&mut self, ident: &Ident, default: &Path, field_type: &Type) {
193209
let encoder = &self.encoder;
@@ -275,6 +291,7 @@ mod tests {
275291
optional: false,
276292
tag_mode: TagMode::Explicit,
277293
constructed: false,
294+
should_deref: false,
278295
};
279296

280297
let field_type = Ident::new("String", span);
@@ -315,6 +332,7 @@ mod tests {
315332
optional: false,
316333
tag_mode: TagMode::Implicit,
317334
constructed: false,
335+
should_deref: false,
318336
};
319337

320338
let field_type = Ident::new("String", span);

0 commit comments

Comments
 (0)