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
1 change: 1 addition & 0 deletions der/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ flagset = { version = "0.4.6", optional = true }
pem-rfc7468 = { version = "1.0.0-rc.1", optional = true, features = ["alloc"] }
time = { version = "0.3.4", optional = true, default-features = false }
zeroize = { version = "1.8", optional = true, default-features = false }
heapless = { version = "0.8", optional = true, default-features = false }

[dev-dependencies]
hex-literal = "1"
Expand Down
21 changes: 21 additions & 0 deletions der/src/asn1/octet_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,27 @@ impl<'a, const N: usize> TryFrom<OctetStringRef<'a>> for [u8; N] {
}
}

#[cfg(feature = "heapless")]
impl<'a, const N: usize> TryFrom<OctetStringRef<'a>> for heapless::Vec<u8, N> {
type Error = Error;

fn try_from(octet_string: OctetStringRef<'a>) -> Result<Self, Self::Error> {
octet_string
.as_bytes()
.try_into()
.map_err(|_| Tag::OctetString.length_error())
}
}

#[cfg(feature = "heapless")]
impl<'a, const N: usize> TryFrom<&'a heapless::Vec<u8, N>> for OctetStringRef<'a> {
type Error = Error;

fn try_from(byte_vec: &'a heapless::Vec<u8, N>) -> Result<Self, Error> {
OctetStringRef::new(byte_vec)
}
}

#[cfg(feature = "alloc")]
pub use self::allocating::OctetString;

Expand Down
79 changes: 0 additions & 79 deletions der/tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,85 +568,6 @@ mod sequence {
assert_eq!(obj, obj_decoded);
}

#[derive(Sequence, Default, Eq, PartialEq, Debug)]
#[asn1(tag_mode = "IMPLICIT")]
pub struct TypeCheckArraysSequenceFieldAttributeCombinations {
#[asn1(type = "OCTET STRING", deref = "true")]
pub array_bytes: [u8; 2],

#[asn1(type = "BIT STRING", deref = "true")]
pub array_bits: [u8; 2],

#[asn1(type = "OCTET STRING", context_specific = "0", deref = "true")]
pub array_implicit_bytes: [u8; 2],

#[asn1(type = "BIT STRING", context_specific = "1", deref = "true")]
pub array_implicit_bits: [u8; 2],

#[asn1(
type = "OCTET STRING",
context_specific = "2",
tag_mode = "EXPLICIT",
deref = "true"
)]
pub array_explicit_bytes: [u8; 2],

#[asn1(
type = "BIT STRING",
context_specific = "3",
tag_mode = "EXPLICIT",
deref = "true"
)]
pub array_explicit_bits: [u8; 2],

#[asn1(type = "BIT STRING", context_specific = "4", optional = "true")]
pub array_optional_implicit_bits: Option<[u8; 2]>,

#[asn1(type = "OCTET STRING", context_specific = "5", optional = "true")]
pub array_optional_implicit_bytes: Option<[u8; 2]>,

#[asn1(
type = "BIT STRING",
context_specific = "6",
optional = "true",
tag_mode = "EXPLICIT"
)]
pub array_optional_explicit_bits: Option<[u8; 2]>,

#[asn1(
type = "OCTET STRING",
context_specific = "7",
optional = "true",
tag_mode = "EXPLICIT"
)]
pub array_optional_explicit_bytes: Option<[u8; 2]>,
}

#[test]
fn type_combinations_arrays_instance() {
let obj = TypeCheckArraysSequenceFieldAttributeCombinations {
array_bytes: [0xAA, 0xBB],
array_bits: [0xCC, 0xDD],

array_implicit_bytes: [0, 1],
array_implicit_bits: [2, 3],

array_explicit_bytes: [4, 5],
array_explicit_bits: [6, 7],

array_optional_implicit_bits: Some([8, 9]),
array_optional_implicit_bytes: Some([10, 11]),

array_optional_explicit_bits: Some([12, 13]),
array_optional_explicit_bytes: Some([14, 15]),
};

let der_encoded = obj.to_der().unwrap();
let obj_decoded =
TypeCheckArraysSequenceFieldAttributeCombinations::from_der(&der_encoded).unwrap();
assert_eq!(obj, obj_decoded);
}

#[derive(Sequence)]
#[asn1(error = CustomError)]
pub struct TypeWithCustomError {
Expand Down
167 changes: 167 additions & 0 deletions der/tests/derive_no_alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//! Tests for custom derive support. Without alloc feature.
//!
//! # Debugging with `cargo expand`
//!
//! To expand the Rust code generated by the proc macro when debugging
//! issues related to these tests, run:
//!
//! $ cargo expand --test derive_heapless --all-features

#![cfg(feature = "derive")]
// TODO: fix needless_question_mark in the derive crate
#![allow(clippy::needless_question_mark)]

/// Custom derive test cases for the `Sequence` macro, without alloc.
mod sequence {
use der::Decode;
use der::Encode;
use der::Sequence;

#[derive(Sequence, Default, Eq, PartialEq, Debug)]
#[asn1(tag_mode = "IMPLICIT")]
pub struct TypeCheckArraysSequenceFieldAttributeCombinations {
#[asn1(type = "OCTET STRING", deref = "true")]
pub array_bytes: [u8; 2],

#[asn1(type = "BIT STRING", deref = "true")]
pub array_bits: [u8; 2],

#[asn1(type = "OCTET STRING", context_specific = "0", deref = "true")]
pub array_implicit_bytes: [u8; 2],

#[asn1(type = "BIT STRING", context_specific = "1", deref = "true")]
pub array_implicit_bits: [u8; 2],

#[asn1(
type = "OCTET STRING",
context_specific = "2",
tag_mode = "EXPLICIT",
deref = "true"
)]
pub array_explicit_bytes: [u8; 2],

#[asn1(
type = "BIT STRING",
context_specific = "3",
tag_mode = "EXPLICIT",
deref = "true"
)]
pub array_explicit_bits: [u8; 2],

#[asn1(type = "BIT STRING", context_specific = "4", optional = "true")]
pub array_optional_implicit_bits: Option<[u8; 2]>,

#[asn1(type = "OCTET STRING", context_specific = "5", optional = "true")]
pub array_optional_implicit_bytes: Option<[u8; 2]>,

#[asn1(
type = "BIT STRING",
context_specific = "6",
optional = "true",
tag_mode = "EXPLICIT"
)]
pub array_optional_explicit_bits: Option<[u8; 2]>,

#[asn1(
type = "OCTET STRING",
context_specific = "7",
optional = "true",
tag_mode = "EXPLICIT"
)]
pub array_optional_explicit_bytes: Option<[u8; 2]>,
}

#[test]
fn type_combinations_arrays_instance() {
let mut buf = [0u8; 100];
let obj = TypeCheckArraysSequenceFieldAttributeCombinations {
array_bytes: [0xAA, 0xBB],
array_bits: [0xCC, 0xDD],

array_implicit_bytes: [0, 1],
array_implicit_bits: [2, 3],

array_explicit_bytes: [4, 5],
array_explicit_bits: [6, 7],

array_optional_implicit_bits: Some([8, 9]),
array_optional_implicit_bytes: Some([10, 11]),

array_optional_explicit_bits: Some([12, 13]),
array_optional_explicit_bytes: Some([14, 15]),
};

let der_encoded = obj.encode_to_slice(&mut buf).unwrap();
let obj_decoded =
TypeCheckArraysSequenceFieldAttributeCombinations::from_der(der_encoded).unwrap();
assert_eq!(obj, obj_decoded);
}
}
/// Custom derive test cases for the `Sequence` macro with heapless crate.
#[cfg(all(feature = "oid", feature = "heapless"))]
mod sequence_heapless_vec {
use der::Decode;
use der::Encode;
use der::Sequence;
use der::asn1::ObjectIdentifier;
use hex_literal::hex;

/// EU Tachograph Gen 2 certificate public key
#[derive(Sequence, Debug, Clone)]
#[asn1(tag_mode = "IMPLICIT")]
pub struct G2CertificatePublicKey {
pub domain_parameters: ObjectIdentifier,

/// Public point is '04 xx .. xx yy .. yy'
///
/// Maximum: 1 + 2 * 66 bytes for Nist521
#[asn1(context_specific = "6", type = "OCTET STRING", deref = "true")]
pub public_point: heapless::Vec<u8, 133>,
}

static ROMANIA_PUBLIC_KEY: [u8; 80] = hex!(
"
30 4E 06 09 2B 24 03 03 02 08 01 01 07 86 41
04 86 23 90 68 B8 08 1F 5E 6B 49 EB 54 F7 8E 0D
FB E7 1F 85 26 15 60 73 7C 24 B0 10 24 F9 2A 02
03 67 80 3E 17 E9 F2 6E D5 A5 4E 25 F9 B5 46 B1
90 3C DD 76 47 DB 1D 8E E0 D9 86 D0 64 D8 3C DD
7F"
);

pub const BRAINPOOL_P_256_R_1: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.36.3.3.2.8.1.1.7");

#[test]
fn heapless_vec_decode_encode() {
let public_key = G2CertificatePublicKey::from_der(&ROMANIA_PUBLIC_KEY).unwrap();

assert_eq!(public_key.domain_parameters, BRAINPOOL_P_256_R_1);
assert_eq!(public_key.public_point.len(), 1 + 2 * (256 / 8));

let mut buf = [0u8; 80];
let pk_encoded = public_key.encode_to_slice(&mut buf).unwrap();

assert_eq!(pk_encoded, ROMANIA_PUBLIC_KEY);
}

#[derive(Sequence, Debug, Clone)]
pub struct HeaplessTypeCheck {
#[asn1(type = "OCTET STRING", deref = "true")]
pub octet_string_heapless: heapless::Vec<u8, 16>,

#[asn1(type = "OCTET STRING", deref = "true", tag_mode = "IMPLICIT")]
pub octet_string_heapless_implicit: heapless::Vec<u8, 16>,

#[asn1(context_specific = "0", type = "OCTET STRING", optional = "true")]
pub opt_octet_string_heapless: Option<heapless::Vec<u8, 16>>,

#[asn1(
context_specific = "1",
type = "OCTET STRING",
optional = "true",
tag_mode = "IMPLICIT"
)]
pub opt_octet_string_heapless_implicit: Option<heapless::Vec<u8, 16>>,
}
}