Skip to content

Commit 5f6ca83

Browse files
callumadairbaloodishmaker
authored
cms: Implement types from RFC 6031 - Cryptographic Message Syntax (CMS) Symmetric Key Package Content Type (#1952)
* first implementation of the symmetric key package types * first implementation of the pksc attribute types * add missing doc comment * Accept suggestion for `s_keys` Co-authored-by: Arthur Gautier <[email protected]> * add asn1 type definition for onesymmetrickey Co-authored-by: Arthur Gautier <[email protected]> * change min and max in ChallengeFormat to intrefs due their potential to be up to Integer MAX in value. * replace Utf8StringRef values with String as appropriate. * Remove redundant lifetimes as suggested by reviewer Co-authored-by: Arthur Gautier <[email protected]> * fix doc comment with suggestion Co-authored-by: dishmaker <[email protected]> * add enums for string values using declarative macro provided by Arthur Gautier. --------- Co-authored-by: Arthur Gautier <[email protected]> Co-authored-by: dishmaker <[email protected]>
1 parent eccdd11 commit 5f6ca83

File tree

2 files changed

+349
-0
lines changed

2 files changed

+349
-0
lines changed

cms/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ pub mod enveloped_data;
4040
pub mod kemri;
4141
pub mod revocation;
4242
pub mod signed_data;
43+
pub mod symmetric_key;
4344
pub mod timestamped_data;

cms/src/symmetric_key.rs

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
//! SymmetricKeyPackage types
2+
3+
use alloc::{string::String, vec::Vec};
4+
use der::ErrorKind;
5+
use der::asn1::Utf8StringRef;
6+
use der::{
7+
DecodeValue, EncodeValue, Enumerated, FixedTag, Header, Length, Reader, Sequence, Tag, Writer,
8+
asn1::OctetString,
9+
};
10+
use x509_cert::attr::Attribute;
11+
12+
macro_rules! impl_str_enum {
13+
(
14+
$(#[$attr:meta])* $vis: vis enum $name: ident {
15+
$( $(#[$attr_item: meta])* $item: ident => $value: expr,)*
16+
}
17+
)=> {
18+
$(#[$attr])*
19+
$vis enum $name {
20+
$( $(#[$attr_item])* $item, )*
21+
}
22+
23+
impl AsRef<str> for $name {
24+
fn as_ref(&self) -> &str {
25+
match self {
26+
$( Self::$item => $value, )*
27+
}
28+
}
29+
}
30+
31+
impl<'d> DecodeValue<'d> for $name {
32+
type Error = der::Error;
33+
34+
fn decode_value<R: Reader<'d>>(reader: &mut R, header: Header) -> der::Result<Self> {
35+
let value = Utf8StringRef::decode_value(reader, header)?;
36+
37+
match value.as_ref() {
38+
$( $value => Ok(Self::$item), )*
39+
_ => Err(der::Error::new(
40+
ErrorKind::Value { tag: Self::TAG },
41+
reader.position(),
42+
)),
43+
}
44+
}
45+
}
46+
47+
impl EncodeValue for $name {
48+
fn value_len(&self) -> der::Result<Length> {
49+
Utf8StringRef::new(self.as_ref())?.value_len()
50+
}
51+
52+
fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
53+
Utf8StringRef::new(self.as_ref())?.encode_value(encoder)
54+
}
55+
}
56+
57+
impl FixedTag for $name {
58+
const TAG: Tag = String::TAG;
59+
}
60+
61+
62+
};
63+
}
64+
65+
/// The `SymmetricKeyPackage` type is defined in [RFC 6031 Section 2.0].
66+
///
67+
/// ```text
68+
/// SymmetricKeyPackage ::= SEQUENCE {
69+
/// version KeyPkgVersion DEFAULT v1,
70+
/// sKeyPkgAttrs [0] SEQUENCE SIZE (1..MAX) OF Attribute
71+
/// {{ SKeyPkgAttributes }} OPTIONAL,
72+
/// sKeys SymmetricKeys,
73+
/// ... }
74+
/// ```
75+
///
76+
/// [RFC 6031 Section 2.0]: https://datatracker.ietf.org/doc/html/rfc6031#section-2
77+
#[derive(Sequence, PartialEq, Eq)]
78+
#[allow(missing_docs)]
79+
pub struct SymmetricKeyPackage {
80+
#[asn1(default = "Default::default")]
81+
pub version: KeyPkgVersion,
82+
#[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")]
83+
pub s_key_pkg_attrs: Option<Vec<Attribute>>,
84+
pub s_keys: SymmetricKeys,
85+
}
86+
87+
/// The `SymmetricKeys` type is defined in [RFC 6031 Section 2.0].
88+
///
89+
/// ```text
90+
/// SymmetricKeys ::= SEQUENCE SIZE (1..MAX) OF OneSymmetricKey
91+
/// ```
92+
///
93+
/// [RFC 6031 Section 2.0]: https://datatracker.ietf.org/doc/html/rfc6031#section-2
94+
pub type SymmetricKeys = Vec<OneSymmetricKey>;
95+
96+
/// The `OneSymmetricKey` type is defined in [RFC 6031 Section 2.0].
97+
///
98+
/// ```text
99+
/// OneSymmetricKey ::= SEQUENCE {
100+
/// sKeyAttrs SEQUENCE SIZE (1..MAX) OF Attribute
101+
/// {{ SKeyAttributes }} OPTIONAL,
102+
/// sKey OCTET STRING OPTIONAL }
103+
/// ( WITH COMPONENTS { ..., sKeyAttrs PRESENT } |
104+
/// WITH COMPONENTS { ..., sKey PRESENT } )
105+
/// ```
106+
///
107+
/// [RFC 6031 Section 2.0]: https://datatracker.ietf.org/doc/html/rfc6031#section-2
108+
#[derive(Sequence, PartialEq, Eq)]
109+
#[allow(missing_docs)]
110+
pub struct OneSymmetricKey {
111+
pub s_key_attrs: Vec<Attribute>,
112+
#[asn1(optional = "true")]
113+
pub s_key: Option<OctetString>,
114+
}
115+
116+
/// The `KeyPkgVersion` type is defined in [RFC 6031 Section 2.0].
117+
///
118+
/// ```text
119+
/// KeyPkgVersion ::= INTEGER { v1(1) } ( v1, ... )
120+
/// ```
121+
/// [RFC 6031 Section 2.0]: https://datatracker.ietf.org/doc/html/rfc6031#section-2
122+
#[derive(Default, Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Enumerated)]
123+
#[asn1(type = "INTEGER")]
124+
#[repr(u8)]
125+
#[allow(missing_docs)]
126+
pub enum KeyPkgVersion {
127+
#[default]
128+
V1 = 1,
129+
}
130+
131+
// todo: determine if all the types below should live in another file such as attr.rs
132+
133+
/// The `FriendlyName` type is defined in [RFC 6031 Section 3.2.6].
134+
///
135+
/// ```text
136+
/// FriendlyName ::= SEQUENCE {
137+
/// friendlyName UTF8String,
138+
/// friendlyNameLangTag UTF8String OPTIONAL }
139+
/// ```
140+
///
141+
/// [RFC 6031 Section 3.2.6]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.2.6
142+
#[derive(Sequence, PartialEq, Eq)]
143+
#[allow(missing_docs)]
144+
pub struct FriendlyName {
145+
pub friendly_name: String,
146+
#[asn1(optional = "true")]
147+
pub friendly_name_lang_tag: Option<String>,
148+
}
149+
150+
/// The `PSKCAlgorithmParameters` type is defined in [RFC 6031 Section 3.2.7].
151+
///
152+
/// ```text
153+
/// PSKCAlgorithmParameters ::= CHOICE {
154+
/// suite UTF8String,
155+
/// challengeFormat [0] ChallengeFormat,
156+
/// responseFormat [1] ResponseFormat,
157+
/// ... }
158+
/// ```
159+
///
160+
/// [RFC 6031 Section 3.2.7]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.2.7
161+
#[derive(Sequence, PartialEq, Eq)]
162+
#[allow(missing_docs)]
163+
pub struct PSKCAlgorithmParameters {
164+
pub suite: String,
165+
pub challenge_format: ChallengeFormat,
166+
pub response_format: ResponseFormat,
167+
}
168+
169+
/// The `ChallengeFormat` type is defined in [RFC 6031 Section 3.2.7].
170+
///
171+
/// ```text
172+
/// ChallengeFormat ::= SEQUENCE {
173+
/// encoding Encoding,
174+
/// checkDigit BOOLEAN DEFAULT FALSE,
175+
/// min INTEGER (0..MAX),
176+
/// max INTEGER (0..MAX),
177+
/// ... }
178+
/// ```
179+
///
180+
/// [RFC 6031 Section 3.2.7]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.2.7
181+
#[derive(Sequence, PartialEq, Eq)]
182+
#[allow(missing_docs)]
183+
pub struct ChallengeFormat {
184+
pub encoding: Encoding,
185+
#[asn1(default = "Default::default")]
186+
pub check_digit: bool,
187+
pub min: der::asn1::Int,
188+
pub max: der::asn1::Int,
189+
}
190+
191+
impl_str_enum!(
192+
/// The `Encoding` type is defined in [RFC 6031 Section 3.2.7].
193+
///
194+
/// ```text
195+
/// Encoding ::= UTF8STRING ("DECIMAL" | "HEXADECIMAL" |
196+
/// "ALPHANUMERIC" |"BASE64" |"BINARY")
197+
/// ```
198+
///
199+
/// [RFC 6031 Section 3.2.7]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.2.7
200+
#[derive(Copy, Clone, PartialEq, Eq)]
201+
pub enum Encoding {
202+
/// "DECIMAL"
203+
Decimal => "DECIMAL",
204+
/// "HEXADECIMAL",
205+
Hexadecimal => "HEXADECIMAL",
206+
/// "ALPHANUMERIC",
207+
Alphanumeric => "ALPHANUMERIC",
208+
/// "BASE64",
209+
Base64 => "BASE64",
210+
/// "BINARY",
211+
Binary => "BINARY",
212+
}
213+
);
214+
215+
/// The `ResponseFormat` type is defined in [RFC 6031 Section 3.2.7].
216+
///
217+
/// ```text
218+
/// ResponseFormat ::= SEQUENCE {
219+
/// encoding Encoding,
220+
/// length INTEGER (0..MAX),
221+
/// checkDigit BOOLEAN DEFAULT FALSE,
222+
/// ... }
223+
/// ```
224+
///
225+
/// [RFC 6031 Section 3.2.7]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.2.7
226+
#[derive(Sequence, PartialEq, Eq)]
227+
#[allow(missing_docs)]
228+
pub struct ResponseFormat {
229+
pub encoding: Encoding,
230+
pub length: u32,
231+
#[asn1(default = "Default::default")]
232+
pub check_digit: bool,
233+
}
234+
235+
/// The `ValueMac` type is defined in [RFC 6031 Section 3.2.12].
236+
///
237+
/// ```text
238+
/// ValueMac ::= SEQUENCE {
239+
/// macAlgorithm UTF8String,
240+
/// mac UTF8String }
241+
/// ```
242+
///
243+
/// [RFC 6031 Section 3.2.12]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.2.12
244+
#[derive(Sequence, PartialEq, Eq)]
245+
#[allow(missing_docs)]
246+
pub struct ValueMac {
247+
pub mac_algorithm: String,
248+
pub mac: String,
249+
}
250+
251+
/// The `PSKCKeyUsages` type is defined in [RFC 6031 Section 3.3.4].
252+
///
253+
/// ```text
254+
/// PSKCKeyUsages ::= SEQUENCE OF PSKCKeyUsage
255+
/// ```
256+
///
257+
/// [RFC 6031 Section 3.3.4]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.3.4
258+
pub type PSKCKeyUsages = Vec<PSKCKeyUsage>;
259+
260+
impl_str_enum!(
261+
/// The `PSKCKeyUsage` type is defined in [RFC 6031 Section 3.3.4].
262+
///
263+
/// ```text
264+
/// PSKCKeyUsage ::= UTF8String ("OTP" | "CR" | "Encrypt" |
265+
/// "Integrity" | "Verify" | "Unlock" | "Decrypt" |
266+
/// "KeyWrap" | "Unwrap" | "Derive" | "Generate")
267+
/// ```
268+
///
269+
/// [RFC 6031 Section 3.3.4]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.3.4
270+
#[derive(Copy, Clone, PartialEq, Eq)]
271+
pub enum PSKCKeyUsage {
272+
/// "OTP"
273+
Otp => "Otp",
274+
/// "CR"
275+
Cr => "CR",
276+
/// "Encrypt"
277+
Encrypt => "Encrypt",
278+
/// "Integrity"
279+
Integrity => "Integrity",
280+
/// "Verify"
281+
Verify => "Verify",
282+
/// "Unlock"
283+
Unlock => "Unlock",
284+
/// "Decrypt"
285+
Decrypt => "Decrypt",
286+
/// "KeyWrap"
287+
KeyWrap => "KeyWrap",
288+
/// "Unwrap"
289+
Unwrap => "Unwrap",
290+
/// "Derive"
291+
Derive => "Derive",
292+
/// "Generate"
293+
Generate => "Generate",
294+
}
295+
);
296+
297+
/// The `PINPolicy` type is defined in [RFC 6031 Section 3.3.5]
298+
///
299+
/// ```text
300+
/// PINPolicy ::= SEQUENCE {
301+
/// pinKeyId [0] UTF8String OPTIONAL,
302+
/// pinUsageMode [1] PINUsageMode,
303+
/// maxFailedAttempts [2] INTEGER (0..MAX) OPTIONAL,
304+
/// minLength [3] INTEGER (0..MAX) OPTIONAL,
305+
/// maxLength [4] INTEGER (0..MAX) OPTIONAL,
306+
/// pinEncoding [5] Encoding OPTIONAL }
307+
/// ```
308+
///
309+
/// [RFC 6031 Section 3.3.5]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.3.5
310+
#[derive(Sequence, PartialEq, Eq)]
311+
#[allow(missing_docs)]
312+
pub struct PINPolicy {
313+
#[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")]
314+
pub pin_key_id: Option<String>,
315+
#[asn1(context_specific = "1", tag_mode = "IMPLICIT")]
316+
pub pin_usage_mode: PINUsageMode,
317+
#[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
318+
pub max_failed_attempts: Option<u32>,
319+
#[asn1(context_specific = "3", tag_mode = "IMPLICIT", optional = "true")]
320+
pub min_length: Option<u32>,
321+
#[asn1(context_specific = "4", tag_mode = "IMPLICIT", optional = "true")]
322+
pub max_length: Option<u32>,
323+
#[asn1(context_specific = "5", tag_mode = "IMPLICIT", optional = "true")]
324+
pub pin_encoding: Option<Encoding>,
325+
}
326+
327+
impl_str_enum!(
328+
329+
/// The `PINUsageMode` type is defined in [RFC 6031 Section 3.3.5]
330+
///
331+
/// ```text
332+
/// PINUsageMode ::= UTF8String ("Local" | "Prepend" | "Append" |
333+
/// "Algorithmic")
334+
/// ```
335+
///
336+
/// [RFC 6031 Section 3.3.5]: https://datatracker.ietf.org/doc/html/rfc6031#section-3.3.5
337+
#[derive(Copy, Clone, PartialEq, Eq)]
338+
pub enum PINUsageMode {
339+
/// "Local"
340+
Local => "Local",
341+
/// "Prepend"
342+
Prepend => "Prepend",
343+
/// "Append"
344+
Append => "Append",
345+
/// "Algorithmic"
346+
Algorithmic => "Algorithmic",
347+
}
348+
);

0 commit comments

Comments
 (0)