Skip to main content

rasn_its/ieee1609dot2/
mod.rs

1extern crate alloc;
2use crate::delegate;
3use crate::ts103097::extension_module::*;
4use alloc::string::ToString;
5use bon::Builder;
6use rasn::error::InnerSubtypeConstraintError;
7use rasn::prelude::*;
8
9/// IEEE 1609.2 Base Types
10/// Based on <https://forge.etsi.org/rep/ITS/asn1/ieee1609.2>
11pub mod base_types;
12/// IEEE 1609.2 CRL Base Types
13pub mod crl_base_types;
14use base_types::*;
15
16/// OID for IEEE 1609.2 module
17pub const IEEE1609_DOT2_OID: &Oid = Oid::const_new(&[
18    1,    // iso
19    3,    // identified-organization
20    111,  // ieee
21    2,    // standards-association-numbered-series-standards
22    1609, // wave-stds
23    2,    // dot2
24    1,    // base
25    1,    // schema
26    2,    // major-version-2
27    6,    // minor-version-6
28]);
29
30pub const CERT_EXT_ID_OPERATING_ORGANIZATION: ExtId = ExtId(1);
31pub const P2PCD8_BYTE_LEARNING_REQUEST_ID: ExtId = ExtId(1);
32
33//***************************************************************************
34//                               Secured Data
35//***************************************************************************
36
37/// Contains other data types in this clause.
38///
39/// # Fields
40/// - `protocol_version`: Current version of the protocol (version 3, represented
41///   by integer 3). There are no major or minor version numbers.
42/// - `content`: Contains the content in the form of an `Ieee1609Dot2Content`
43///
44/// # Canonicalization
45/// Subject to canonicalization for operations specified in 6.1.2.
46/// The canonicalization applies to the `Ieee1609Dot2Content`.
47#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
48#[rasn(automatic_tags)]
49pub struct Ieee1609Dot2Data {
50    #[builder(default = Ieee1609Dot2Data::VERSION)]
51    #[rasn(value("3"), identifier = "protocolVersion")]
52    pub protocol_version: Uint8,
53    pub content: Ieee1609Dot2Content,
54}
55impl Ieee1609Dot2Data {
56    pub const VERSION: u8 = 3;
57}
58
59/// Content types for IEEE 1609.2 data structures.
60///
61/// # Variants
62/// - `UnsecuredData`: OCTET STRING to be consumed outside the SDS
63/// - `SignedData`: Content signed according to this standard
64/// - `EncryptedData`: Content encrypted according to this standard
65/// - `SignedCertificateRequest`: Certificate request signed by an IEEE 1609.2
66///   certificate or self-signed
67/// - `SignedX509CertificateRequest`: Certificate request signed by an ITU-T X.509
68///   certificate
69///
70/// # Canonicalization
71/// Subject to canonicalization for operations specified in 6.1.2 when type is
72/// `SignedData`. The canonicalization applies to the `SignedData` structure.
73#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
74#[rasn(choice, automatic_tags)]
75#[non_exhaustive]
76pub enum Ieee1609Dot2Content {
77    UnsecuredData(Opaque),
78    SignedData(alloc::boxed::Box<SignedData>),
79    EncryptedData(EncryptedData),
80    SignedCertificateRequest(Opaque),
81    #[rasn(extension_addition)]
82    SignedX509CertificateRequest(Opaque),
83}
84/// Structure containing signed data and signature information.
85///
86/// # Fields
87/// - `hash_id`: Hash algorithm used to generate the message hash for signing
88///   and verification
89/// - `tbs_data`: Data that is hashed as input to the signature
90/// - `signer`: Determines keying material and hash algorithm used to sign the data
91/// - `signature`: Digital signature calculated as specified in 5.3.1
92///
93/// # Signature Calculation
94/// ## For Self-Signed
95/// When `signer` indicates "self":
96/// - Data input: COER encoding of `tbs_data` field (canonicalized per 6.3.6)
97/// - Verification type: self
98/// - Signer identifier input: empty string
99///
100/// ## For Certificate or Digest
101/// When `signer` indicates "certificate" or "digest":
102/// - Data input: COER encoding of `tbs_data` field (canonicalized per 6.3.6)
103/// - Verification type: certificate
104/// - Signer identifier input: COER-encoding of the Certificate used for
105///   verification (canonicalized per 6.4.3)
106///
107/// # Canonicalization
108/// Subject to canonicalization for operations specified in 6.1.2.
109/// Applies to both `ToBeSignedData` and `Signature`.
110#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
111#[rasn(automatic_tags)]
112pub struct SignedData {
113    #[rasn(identifier = "hashId")]
114    pub hash_id: HashAlgorithm,
115    #[rasn(identifier = "tbsData")]
116    pub tbs_data: ToBeSignedData,
117    pub signer: SignerIdentifier,
118    pub signature: Signature,
119}
120/// Contains the data to be hashed when generating or verifying a signature.
121/// See section 6.3.4 for hash input specification.
122///
123/// # Fields
124/// - `payload`: Data provided by the entity invoking the SDS
125/// - `header_info`: Additional data inserted by the SDS
126///
127/// # Hash Operation Input
128/// The data input to the hash operation (per 5.3.1.2.2 or 5.3.1.3) is determined as follows:
129///
130/// ## When payload is present
131/// - Uses COER encoding of the `ToBeSignedData`
132///
133/// ## When payload is omitted
134/// - Uses concatenation of:
135///   1. COER encoding of the `ToBeSignedData`
136///   2. Hash of the omitted payload (using same hash algorithm as main operation)
137/// - No additional wrapping or length indication
138/// - Method for establishing omitted payload contents between signer and verifier
139///   is out of scope (see 5.2.4.3.4)
140///
141/// # Canonicalization
142/// Subject to canonicalization for operations specified in 6.1.2.
143/// Applies to:
144/// - `SignedDataPayload` (when type is "data")
145/// - `HeaderInfo`
146#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
147#[rasn(automatic_tags)]
148pub struct ToBeSignedData {
149    pub payload: SignedDataPayload,
150    #[rasn(identifier = "headerInfo")]
151    pub header_info: HeaderInfo,
152}
153
154/// Contains the data payload of a `ToBeSignedData`. Must contain at least one
155/// optional element, and may contain multiple. See section 5.2.4.3.4 for details.
156///
157/// # Implementation Support
158/// The security profile in Annex C allows implementations to specify:
159/// - Supported forms of `SignedDataPayload`
160/// - Methods for signers and verifiers to obtain external data for hashing
161///
162/// SDEE specifications using external data must explicitly define:
163/// - How to obtain the data
164/// - How to format the data before hash processing
165///
166/// # Fields
167/// - `data`: Data explicitly transported within the structure
168/// - `ext_data_hash`: Hash of data not explicitly transported, which the creator
169///   wishes to cryptographically bind to the signature
170/// - `omitted`: Indicates external data to be included in signature hash calculation
171///   (mechanism specified in 6.3.6)
172///
173/// # Canonicalization
174/// Subject to canonicalization for operations specified in 6.1.2.
175/// The canonicalization applies to the `Ieee1609Dot2Data`.
176#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
177#[rasn(automatic_tags)]
178#[non_exhaustive]
179pub struct SignedDataPayload {
180    pub data: Option<Ieee1609Dot2Data>,
181    #[rasn(identifier = "extDataHash")]
182    pub ext_data_hash: Option<HashedData>,
183    #[rasn(extension_addition)]
184    pub omitted: Option<()>,
185}
186
187#[bon::bon]
188impl SignedDataPayload {
189    #[builder]
190    pub fn new(
191        data: Option<Ieee1609Dot2Data>,
192        ext_data_hash: Option<HashedData>,
193        omitted: Option<()>,
194    ) -> Result<Self, InnerSubtypeConstraintError> {
195        Self {
196            data,
197            ext_data_hash,
198            omitted,
199        }
200        .validate_components()
201    }
202}
203
204impl InnerSubtypeConstraint for SignedDataPayload {
205    fn validate_and_decode_containing(
206        self,
207        _: Option<rasn::Codec>,
208    ) -> Result<Self, rasn::error::InnerSubtypeConstraintError> {
209        if self.data.is_none() && self.ext_data_hash.is_none() && self.omitted.is_none() {
210            return Err(InnerSubtypeConstraintError::MissingRequiredComponent {
211                component_path: "SignedDataPayload",
212                components: &["data", "ext_data_hash", "omitted"],
213            });
214        }
215        Ok(self)
216    }
217}
218
219/// Contains the hash of data with a specified hash algorithm. See section 5.3.3
220/// for permitted hash algorithms.
221///
222/// # Variants
223/// - `Sha256HashedData`: Data hashed with SHA-256
224/// - `Sha384HashedData`: Data hashed with SHA-384
225/// - `Sm3HashedData`: Data hashed with SM3
226///
227/// # Critical Information Field
228/// This is a critical information field as defined in 5.2.6:
229/// - An implementation that does not recognize the indicated CHOICE when verifying
230///   a signed SPDU shall indicate that the SPDU is invalid (per 4.2.2.3.2)
231/// - Invalid in this context means its validity cannot be established
232#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
233#[rasn(choice, automatic_tags)]
234#[non_exhaustive]
235pub enum HashedData {
236    Sha256HashedData(HashedId32),
237    #[rasn(extension_addition)]
238    Sha384HashedData(HashedId48),
239    #[rasn(extension_addition)]
240    Sm3HashedData(HashedId32),
241}
242
243/// Contains information used to establish validity per criteria in section 5.2.
244///
245/// # Fields
246/// - `psid`: Application area with which sender claims payload association
247///
248/// - `generation_time`: Time of structure generation (see 5.2.5.2.2 and 5.2.5.2.3)
249///
250/// - `expiry_time`: Time after which data is no longer relevant
251///   - If both `generation_time` and `expiry_time` present, SPDU is invalid if
252///     `generation_time` is not strictly earlier than `expiry_time`
253///
254/// - `generation_location`: Location where signature was generated
255///
256/// - `p2pcd_learning_request`: Used to request certificates with known identifiers
257///   but unknown full content
258///   - Used for separate-certificate-pdu P2PCD (Clause 8)
259///   - Mutually exclusive with `inline_p2pcd_request`
260///   - `HashedId3` calculated using whole-certificate hash algorithm (see 6.4.3)
261///
262/// - `missing_crl_identifier`: For requesting known-issued but unreceived CRLs
263///   (reserved for future use)
264///
265/// - `encryption_key`: Key for encrypting response SPDUs
266///   - SDEE specification defines which responses use this key
267///   - See 6.3.35, 6.3.37, and 6.3.34 for usage details
268///   - Symmetric key type should only be used with encrypted SignedData
269///
270/// - `inline_p2pcd_request`: For requesting unknown certificates via inline P2PCD
271///   - Mutually exclusive with `p2pcd_learning_request`
272///   - `HashedId3` calculated as per 6.4.3
273///
274/// - `requested_certificate`: Provides certificates for inline P2PCD (Clause 8)
275///
276/// - `pdu_functional_type`: Indicates SPDU consumption by non-application process
277///   (ISO 21177 B14a, see 6.3.23b)
278///
279/// - `contributed_extensions`: Additional extensions using `ContributedExtensionBlocks`
280///
281/// # Canonicalization
282/// Subject to canonicalization for operations specified in 6.1.2:
283/// - Applies to `EncryptionKey`
284/// - For public `EncryptionKey` with elliptic curve points (`EccP256CurvePoint` or
285///   `EccP384CurvePoint`):
286///   - Points must be in compressed form (`compressed-y-0` or `compressed-y-1`)
287/// - Does not apply to fields after extension marker, including `contributed_extensions`
288#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
289#[rasn(automatic_tags)]
290#[non_exhaustive]
291pub struct HeaderInfo {
292    pub psid: Psid,
293    #[rasn(identifier = "generationTime")]
294    pub generation_time: Option<Time64>,
295    #[rasn(identifier = "expiryTime")]
296    pub expiry_time: Option<Time64>,
297    #[rasn(identifier = "generationLocation")]
298    pub generation_location: Option<ThreeDLocation>,
299    #[rasn(identifier = "p2pcdLearningRequest")]
300    pub p2pcd_learning_request: Option<HashedId3>,
301    #[rasn(identifier = "missingCrlIdentifier")]
302    pub missing_crl_identifier: Option<MissingCrlIdentifier>,
303    #[rasn(identifier = "encryptionKey")]
304    pub encryption_key: Option<EncryptionKey>,
305    #[rasn(extension_addition, identifier = "inlineP2pcdRequest")]
306    pub inline_p2pcd_request: Option<SequenceOfHashedId3>,
307    #[rasn(extension_addition, identifier = "requestedCertificate")]
308    pub requested_certificate: Option<Certificate>,
309    #[rasn(extension_addition, identifier = "pduFunctionalType")]
310    pub pdu_functional_type: Option<PduFunctionalType>,
311    #[rasn(extension_addition, identifier = "contributedExtensions")]
312    pub contributed_extensions: Option<ContributedExtensionBlocks>,
313}
314
315/// Structure for requesting a known-issued but unreceived CRL.
316/// Provided for future use; not defined in current standard version.
317///
318/// # Fields
319/// - `craca_id`: HashedId3 of the CRACA (defined in 5.1.3)
320///   - Calculated using whole-certificate hash algorithm (per 6.4.3)
321///   - Applied to COER-encoded certificate
322///   - Certificate must be canonicalized per Certificate definition
323///
324/// - `crl_series`: Requested CRL Series value (see 5.1.3 for details)
325#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
326#[rasn(automatic_tags)]
327#[non_exhaustive]
328pub struct MissingCrlIdentifier {
329    #[rasn(identifier = "cracaId")]
330    pub craca_id: HashedId3,
331    #[rasn(identifier = "crlSeries")]
332    pub crl_series: CrlSeries,
333}
334
335/// Identifies the functional entity intended to consume an SPDU, specifically for
336/// security support services rather than application processes.
337/// Further details defined in ISO 21177 B20.
338///
339/// # Values
340/// - `1`: TLS Handshake
341///   - Not for direct application PDU consumption
342///   - Used for securing communications to application process
343///   - Provides holder's permissions to TLS handshake
344///   - References: IETF 5246 B15, IETF 8446 B16, ISO 21177 B20
345///
346/// - `2`: ISO 21177 Extended Auth
347///   - Not for direct application PDU consumption
348///   - Provides additional holder permissions information
349///   - See ISO 21177 B20 for details
350///
351/// - `3`: ISO 21177 Session Extension
352///   - Not for direct application PDU consumption
353///   - Enables session persistence beyond certificate lifetime
354#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
355#[rasn(delegate, value("0..=255"))]
356pub struct PduFunctionalType(pub u8);
357
358delegate!(u8, PduFunctionalType);
359
360/// TLS Handshake process
361pub const TLS_HANDSHAKE: PduFunctionalType = PduFunctionalType(1);
362/// ISO 21177 Extended Authentication
363pub const ISO21177_EXTENDED_AUTH: PduFunctionalType = PduFunctionalType(2);
364/// ISO 21177 Session Extension
365pub const ISO21177_SESSION_EXTENSION: PduFunctionalType = PduFunctionalType(3);
366
367/// This type is used for clarity of definitions.
368#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
369#[rasn(delegate, size("1.."))]
370pub struct ContributedExtensionBlocks(pub SequenceOf<ContributedExtensionBlockType>);
371
372delegate!(
373    SequenceOf<ContributedExtensionBlockType>,
374    ContributedExtensionBlocks
375);
376
377pub trait HeaderInfoContributedExtension {
378    type Extn: AsnType + Encode + Decode;
379    const ID: HeaderInfoContributorId;
380}
381
382#[derive(AsnType, Copy, Clone, Debug, Encode, Decode, PartialEq, Eq, Hash)]
383#[rasn(enumerated)]
384#[non_exhaustive]
385pub enum Ieee1609HeaderInfoExtensions {}
386
387impl ExtType for Ieee1609HeaderInfoExtensions {
388    type ExtContent = HashedId8;
389    const EXT_ID: ExtId = P2PCD8_BYTE_LEARNING_REQUEST_ID;
390}
391
392impl HeaderInfoContributedExtension for Ieee1609ContributedHeaderInfoExtension {
393    type Extn = Extension<Ieee1609HeaderInfoExtensions>;
394    const ID: HeaderInfoContributorId = IEEE1609_HEADER_INFO_CONTRIBUTOR_ID;
395}
396impl HeaderInfoContributedExtension for EtsiOriginatingHeaderInfoExtension {
397    type Extn = EtsiOriginatingHeaderInfoExtension;
398    const ID: HeaderInfoContributorId = ETSI_HEADER_INFO_CONTRIBUTOR_ID;
399}
400
401/// Uses the parameterized type `Extension` to define an
402/// `Ieee1609ContributedHeaderInfoExtension`.
403///
404/// Contains an open Extension Content field identified by an extension identifier.
405/// The extension identifier value is:
406/// - Unique within ETSI-defined extensions
407/// - Not required to be unique across all contributing organizations
408#[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
409pub struct Ieee1609ContributedHeaderInfoExtension(pub Extension<Ieee1609HeaderInfoExtensions>);
410
411delegate!(
412    Extension<Ieee1609HeaderInfoExtensions>,
413    Ieee1609ContributedHeaderInfoExtension
414);
415
416/// Defines the format of an extension block provided by an identified contributor.
417///
418/// Uses the template from `IEEE1609DOT2-HEADERINFO-CONTRIBUTED-EXTENSION` class
419/// constraint applied to objects in `Ieee1609Dot2HeaderInfoContributedExtensions`.
420///
421/// # Fields
422/// - `contributor_id`: Uniquely identifies the contributor
423/// - `extns`: List of extensions from that contributor
424///   - Extensions typically follow format specified in section 6.5,
425///     but this is not required
426#[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
427pub struct ContributedExtensionBlock<T: HeaderInfoContributedExtension> {
428    #[rasn(identifier = "contributorId")]
429    pub contributor_id: HeaderInfoContributorId,
430    #[rasn(size("1.."))]
431    pub extns: SequenceOf<T::Extn>,
432}
433
434#[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
435#[rasn(choice)]
436#[rasn(automatic_tags)]
437#[non_exhaustive]
438pub enum ContributedExtensionBlockType {
439    Ieee1609(ContributedExtensionBlock<Ieee1609ContributedHeaderInfoExtension>),
440    Etsi(ContributedExtensionBlock<EtsiOriginatingHeaderInfoExtension>),
441}
442
443/// Integer identifying a HeaderInfo extension contributing organization.
444///
445/// # Defined Values
446/// - `1` (IEEE1609): Extensions originating with IEEE 1609
447/// - `2` (ETSI): Extensions originating with ETSI TC ITS
448#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
449#[rasn(delegate)]
450pub struct HeaderInfoContributorId(pub u8);
451
452delegate!(u8, HeaderInfoContributorId);
453
454// Defined contributor IDs
455pub const ETSI_HEADER_INFO_CONTRIBUTOR_ID: HeaderInfoContributorId = HeaderInfoContributorId(2);
456pub const IEEE1609_HEADER_INFO_CONTRIBUTOR_ID: HeaderInfoContributorId = HeaderInfoContributorId(1);
457
458/// Allows recipients to determine which keying material to use for data
459/// authentication and indicates the verification type for hash generation
460/// (specified in 5.3.1).
461///
462/// # Variants
463/// ## Digest
464/// Contains HashedId8 of the relevant certificate:
465/// - Calculated with whole-certificate hash algorithm (per 6.4.3)
466/// - Verification type: certificate
467/// - Certificate data passed to hash function is authorization certificate
468///
469/// ## Certificate
470/// Contains one or more Certificate structures:
471/// - First certificate is authorization certificate
472/// - Subsequent certificates are issuers of preceding certificates
473/// - Verification type: certificate
474/// - Certificate data passed to hash function is authorization certificate
475///
476/// ## SelfSigned
477/// - Contains no additional data
478/// - Verification type: self-signed
479///
480/// # Critical Information Fields
481/// This is a critical information field (5.2.6):
482/// - Implementation must recognize CHOICE value when verifying signed SPDU
483/// - For Certificate variant:
484///   - Must support at least one certificate
485///   - Must support specified number of certificates
486/// - Invalid SPDU if requirements not met
487///
488/// # Canonicalization
489/// Subject to canonicalization for operations specified in 6.1.2:
490/// - Applies to every Certificate in the certificate field
491#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
492#[rasn(choice, automatic_tags)]
493#[non_exhaustive]
494pub enum SignerIdentifier {
495    Digest(HashedId8),
496    Certificate(SequenceOfCertificate),
497    #[rasn(identifier = "self")]
498    SelfSigned(()),
499}
500
501/// This data structure is used to perform a countersignature over an already-signed SPDU.
502///
503/// This is the profile of an Ieee1609Dot2Data containing a signedData.
504/// The tbsData within content is composed of a payload containing the hash
505/// (extDataHash) of the externally generated, pre-signed
506/// SPDU over which the countersignature is performed.
507#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
508#[rasn(delegate)]
509pub struct Countersignature(Ieee1609Dot2Data);
510#[bon::bon]
511impl Countersignature {
512    #[builder]
513    fn new(data: Ieee1609Dot2Data) -> Result<Self, InnerSubtypeConstraintError> {
514        Self(data).validate_components()
515    }
516}
517
518impl InnerSubtypeConstraint for Countersignature {
519    fn validate_and_decode_containing(
520        self,
521        _: Option<rasn::Codec>,
522    ) -> Result<Self, rasn::error::InnerSubtypeConstraintError> {
523        if let Ieee1609Dot2Content::SignedData(ref signed_data) = self.0.content {
524            if let SignedData {
525                tbs_data:
526                    ToBeSignedData {
527                        payload:
528                            SignedDataPayload {
529                                data: None,
530                                ext_data_hash: Some(_),
531                                ..
532                            },
533                        header_info:
534                            HeaderInfo {
535                                generation_time: Some(_),
536                                expiry_time: None,
537                                generation_location: None,
538                                p2pcd_learning_request: None,
539                                missing_crl_identifier: None,
540                                encryption_key: None,
541                                ..
542                            },
543                        ..
544                    },
545                ..
546            } = **signed_data
547            {
548                Ok(self)
549            } else {
550                Err(InnerSubtypeConstraintError::InvalidComponentVariant {
551                    component_path: "Ieee1609Dot2Data.content.tbsData",
552                    component_type: "Ieee1609Dot2Content::SignedData",
553                    details:
554                        "SignedData does not match inner subtype constraint for Countersignature"
555                            .to_string(),
556                })
557            }
558        } else {
559            Err(InnerSubtypeConstraintError::InvalidComponentVariant {
560                component_path: "Ieee1609Dot2Data.content",
561                component_type: "Ieee1609Dot2Content",
562                details: "SignedData variant is required for Countersignature".to_string(),
563            })
564        }
565    }
566}
567
568// ***************************************************************************
569// **                            Encrypted Data                             **
570// ***************************************************************************
571
572/// Encodes data encrypted to one or more recipients using their public or symmetric
573/// keys as specified in 5.3.4.
574///
575/// # Fields
576/// - `recipients`: One or more `RecipientInfo` entries
577///   - May contain multiple types of `RecipientInfo`
578///   - All entries must indicate/contain the same data encryption key
579///
580/// - `ciphertext`: Encrypted data
581///   - Contains encrypted `Ieee1609Dot2Data` structure (per 5.3.4.2)
582///
583/// # Critical Information Fields
584/// The `recipients` field is critical (per 5.2.6):
585/// - Implementation must support specified number of `RecipientInfo` entries
586/// - Must support at least eight entries
587/// - Failure to support required number results in decryption failure
588///
589/// # Raw Data Example
590/// For plaintext that isn't from previous SDS operation, it can be encapsulated
591/// in `Ieee1609Dot2Data` of type `unsecuredData` (per 4.2.2.2.2):
592/// ```text
593/// Raw data:    01 23 45 67 89 AB CD EF
594/// COER encoded: 03 80 08 01 23 45 67 89 AB CD EF
595/// Where:
596/// - 03: protocolVersion
597/// - 80: choice unsecuredData
598/// - 08: length of raw data
599/// ```
600#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
601#[rasn(automatic_tags)]
602pub struct EncryptedData {
603    pub recipients: SequenceOfRecipientInfo,
604    pub ciphertext: SymmetricCiphertext,
605}
606
607/// Transfers data encryption key to individual recipients of `EncryptedData`.
608/// See Annex C.7 for guidance on appropriate use of each approach.
609///
610/// # Variants
611/// ## `PskRecipInfo`
612/// Data encrypted directly using pre-shared symmetric key
613/// - Used with static encryption key approach (5.3.4)
614///
615/// ## `SymmRecipInfo`
616/// Data encrypted with data encryption key, which was encrypted using symmetric key
617/// - Used with ephemeral encryption key approach (5.3.4)
618///
619/// ## `CertRecipInfo`
620/// Data encrypted with data encryption key, which was encrypted using public key from certificate
621/// - Used with ephemeral encryption key approach (5.3.4)
622/// - For ECIES: Parameter P1 (5.3.5) is certificate hash
623///   - Using whole-certificate hash algorithm (6.4.3)
624///   - Applied to COER-encoded, canonicalized certificate
625/// - For SM2: No P1 parameter equivalent
626///
627/// ## `SignedDataRecipInfo`
628/// Data encrypted with data encryption key, which was encrypted using public key from SignedData
629/// - For ECIES: Parameter P1 (5.3.5) is SHA-256 hash of canonicalized `Ieee1609Dot2Data`
630/// - For SM2: No P1 parameter equivalent
631///
632/// ## `RekRecipInfo`
633/// Data encrypted with data encryption key, which was encrypted using public key from other source
634/// - SDEE specification defines public key source
635/// - For ECIES: Parameter P1 (5.3.5) is hash of empty string
636/// - For SM2: No P1 parameter equivalent
637///
638/// # Implementation Note
639/// Encryption key input is raw bytes without headers, encapsulation, or length indication
640/// (unlike data encryption, where data is encapsulated in `Ieee1609Dot2Data`)
641#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
642#[rasn(choice, automatic_tags)]
643pub enum RecipientInfo {
644    PskRecipInfo(PreSharedKeyRecipientInfo),
645    SymmRecipInfo(SymmRecipientInfo),
646    CertRecipInfo(PKRecipientInfo),
647    SignedDataRecipInfo(PKRecipientInfo),
648    RekRecipInfo(PKRecipientInfo),
649}
650
651/// This type is used for clarity of definitions.
652#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
653#[rasn(delegate)]
654pub struct SequenceOfRecipientInfo(pub SequenceOf<RecipientInfo>);
655
656delegate!(SequenceOf<RecipientInfo>, SequenceOfRecipientInfo);
657
658/// Indicates a symmetric key that may be used directly to decrypt a `SymmetricCiphertext`.
659///
660/// # Value Calculation
661/// Contains the low-order 8 bytes of a hash calculated from:
662/// - COER encoding of a `SymmetricEncryptionKey` structure containing the symmetric key
663/// - Hash algorithm determined as specified in 5.3.9.3
664///
665/// # Note
666/// The symmetric key may be established by any appropriate means agreed by the
667/// two parties to the exchange.
668#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
669#[rasn(delegate)]
670pub struct PreSharedKeyRecipientInfo(pub HashedId8);
671
672delegate!(HashedId8, PreSharedKeyRecipientInfo);
673
674/// Contains recipient identification and encrypted data encryption key information.
675///
676/// # Fields
677/// ## `recipient_id`
678/// Hash of the symmetric key encryption key for decrypting the data encryption key:
679/// - Contains low-order 8 bytes of hash
680/// - Calculated from COER encoding of `SymmetricEncryptionKey` structure
681/// - Uses hash algorithm specified in 5.3.9.4
682/// - Symmetric key may be established by any agreed means between parties
683///
684/// ## `enc_key`
685/// Contains encrypted data encryption key in `SymmetricCiphertext`:
686/// - Key is input to encryption process without headers, encapsulation,
687///   or length indication
688#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
689#[rasn(automatic_tags)]
690pub struct SymmRecipientInfo {
691    #[rasn(identifier = "recipientId")]
692    pub recipient_id: HashedId8,
693    #[rasn(identifier = "encKey")]
694    pub enc_key: SymmetricCiphertext,
695}
696
697/// Contains recipient information and encrypted data encryption key.
698///
699/// # Fields
700/// ## `recipient_id`
701/// Contains hash of the encryption public key container, calculated differently
702/// based on the containing `RecipientInfo` structure:
703///
704/// - For `certRecipInfo`:
705///   - Contains `HashedId8` of the certificate
706///   - Calculated using whole-certificate hash algorithm (per 6.4.3)
707///   - Applied to COER-encoded certificate, canonicalized per Certificate definition
708///
709/// - For `signedDataRecipInfo`:
710///   - Contains `HashedId8` of the `Ieee1609Dot2Data` (type signedData)
711///   - Data canonicalized per 6.3.4
712///   - Hash algorithm determined per 5.3.9.5
713///
714/// - For `rekRecipInfo`:
715///   - Contains `HashedId8` of COER-encoded `PublicEncryptionKey`
716///   - Hash algorithm determined per 5.3.9.5
717///
718/// ## `enc_key`
719/// Contains the encrypted data encryption key:
720/// - Key is input to encryption process without headers, encapsulation,
721///   or length indication
722#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
723#[rasn(automatic_tags)]
724pub struct PKRecipientInfo {
725    #[rasn(identifier = "recipientId")]
726    pub recipient_id: HashedId8,
727    #[rasn(identifier = "encKey")]
728    pub enc_key: EncryptedDataEncryptionKey,
729}
730
731/// Contains encrypted data encryption key, input to encryption process without
732/// headers, encapsulation, or length indication.
733///
734/// # Critical Information Field
735/// If present and applicable to receiving SDEE, this is critical (per 5.2.6):
736/// - If implementation receives encrypted SPDU and:
737///   - Determines one or more `RecipientInfo` fields are relevant
738///   - All relevant `RecipientInfos` contain unrecognized CHOICE in
739///     `EncryptedDataEncryptionKey`
740/// - Then implementation must indicate SPDU is not decryptable
741#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
742#[rasn(choice, automatic_tags)]
743#[non_exhaustive]
744pub enum EncryptedDataEncryptionKey {
745    EciesNistP256(EciesP256EncryptedKey),
746    EciesBrainpoolP256r1(EciesP256EncryptedKey),
747    #[rasn(extension_addition)]
748    EcencSm2256(EcencP256EncryptedKey),
749}
750
751/// Encapsulates a ciphertext generated with an approved symmetric algorithm.
752///
753/// # Critical Information Field
754/// This is a critical information field as defined in 5.2.6:
755/// - An implementation that does not recognize the indicated CHOICE value in an
756///   encrypted SPDU shall indicate that the SPDU is invalid (per 4.2.2.3.2)
757/// - Invalid in this context means its validity cannot be established
758#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
759#[rasn(choice, automatic_tags)]
760#[non_exhaustive]
761pub enum SymmetricCiphertext {
762    Aes128ccm(One28BitCcmCiphertext),
763    #[rasn(extension_addition)]
764    Sm4Ccm(One28BitCcmCiphertext),
765}
766
767/// Encapsulates encrypted ciphertext for symmetric algorithms with 128-bit blocks
768/// in CCM mode.
769///
770/// # Characteristics
771/// - Ciphertext is 16 bytes longer than plaintext (includes MAC)
772/// - Successful decryption yields either:
773///   - COER-encoded `Ieee1609Dot2Data` structure (see 6.3.41)
774///   - 16-byte symmetric key (see 6.3.44)
775///
776/// # Fields
777/// - `nonce`: Contains nonce N as specified in 5.3.8
778/// - `ccm_ciphertext`: Contains ciphertext C as specified in 5.3.8
779///
780/// # Name Clarification
781/// The "One28" in the structure name refers to:
782/// - The symmetric cipher block size (128 bits)
783/// - Not the key length (though AES-128-CCM and SM4-CCM happen to use 128-bit keys)
784///
785/// Since the cipher operates in counter mode (stream cipher):
786/// - Block size only affects MAC size
787/// - Does not affect raw ciphertext size
788#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
789#[rasn(automatic_tags)]
790pub struct One28BitCcmCiphertext {
791    pub nonce: FixedOctetString<12>,
792    #[rasn(identifier = "ccmCiphertext")]
793    pub ccm_ciphertext: Opaque,
794}
795
796/// This type is defined only for backwards compatibility.
797#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
798#[rasn(delegate)]
799pub struct Aes128CcmCiphertext(pub One28BitCcmCiphertext);
800
801delegate!(One28BitCcmCiphertext, Aes128CcmCiphertext);
802
803// ***************************************************************************
804// **              Certificates and other Security Management               **
805// ***************************************************************************
806
807/// A profile of the `CertificateBase` structure specifying valid combinations
808/// of fields for transmitting implicit and explicit certificates.
809///
810/// # Canonicalization
811/// Subject to canonicalization for operations specified in 6.1.2:
812/// - Applies to the `CertificateBase`
813#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
814#[rasn(delegate)]
815pub struct Certificate(CertificateBase);
816
817impl From<ImplicitCertificate> for Certificate {
818    fn from(data: ImplicitCertificate) -> Self {
819        Self(data.0)
820    }
821}
822impl From<ExplicitCertificate> for Certificate {
823    fn from(data: ExplicitCertificate) -> Self {
824        Self(data.0)
825    }
826}
827
828impl core::ops::Deref for Certificate {
829    type Target = CertificateBase;
830
831    fn deref(&self) -> &Self::Target {
832        &self.0
833    }
834    // We should not allow mutation of the inner data if they require validation!
835}
836
837#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
838#[rasn(delegate)]
839pub struct TestCertificate(pub Certificate);
840
841delegate!(Certificate, TestCertificate);
842
843/// This type is used for clarity of definitions.
844#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
845#[rasn(delegate)]
846pub struct SequenceOfCertificate(pub SequenceOf<Certificate>);
847
848delegate!(SequenceOf<Certificate>, SequenceOfCertificate);
849
850/// Certificate structure containing version, type, issuer, and content information.
851///
852/// # Fields
853/// - `version`: Certificate format version (set to 3 in this version)
854/// - `c_type`: Indicates explicit or implicit certificate
855/// - `issuer`: Identifies the certificate issuer
856/// - `to_be_signed`: Certificate contents, used in hash generation/verification
857/// - `signature`: Present in `ExplicitCertificate`, calculated over `to_be_signed` hash
858///
859/// # Signature Calculation
860/// Hash calculated as specified in 5.3.1:
861/// - Data input: COER encoding of `to_be_signed`
862/// - Signer identifier input:
863///   - For self-signed (issuer is self): empty string
864///   - Otherwise: Canonicalized COER encoding of issuer's certificate
865///
866/// # Canonicalization
867/// Subject to canonicalization for operations in 6.1.2:
868/// - Applies to `ToBeSignedCertificate` and `Signature`
869///
870/// # Whole-Certificate Hash
871/// Used for calculating `HashedId3`, `HashedId8`, or `HashedId10`:
872/// - Algorithm determined as specified in 5.3.9.2
873#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
874#[rasn(automatic_tags)]
875pub struct CertificateBase {
876    #[rasn(value("3"))]
877    #[builder(default = CertificateBase::VERSION)]
878    pub version: Uint8,
879    #[rasn(identifier = "type")]
880    pub r#type: CertificateType,
881    pub issuer: IssuerIdentifier,
882    #[rasn(identifier = "toBeSigned")]
883    pub to_be_signed: ToBeSignedCertificate,
884    pub signature: Option<Signature>,
885}
886impl CertificateBase {
887    pub const VERSION: u8 = 3;
888    #[must_use]
889    pub const fn is_implicit(&self) -> bool {
890        matches!(
891            &self,
892            CertificateBase {
893                r#type: CertificateType::Implicit,
894                to_be_signed: ToBeSignedCertificate {
895                    verify_key_indicator: VerificationKeyIndicator::ReconstructionValue(_),
896                    ..
897                },
898                signature: None,
899                ..
900            }
901        )
902    }
903    #[must_use]
904    pub const fn is_explicit(&self) -> bool {
905        matches!(
906            self,
907            CertificateBase {
908                r#type: CertificateType::Explicit,
909                to_be_signed: ToBeSignedCertificate {
910                    verify_key_indicator: VerificationKeyIndicator::VerificationKey(_),
911                    ..
912                },
913                signature: Some(_),
914                ..
915            }
916        )
917    }
918}
919
920/// Indicates whether a certificate is explicit or implicit.
921///
922/// # Critical Information Field
923/// This is a critical information field as defined in 5.2.5:
924/// - An implementation that does not recognize the indicated CHOICE when verifying
925///   a signed SPDU shall indicate that the SPDU is invalid (per 4.2.2.3.2)
926/// - Invalid in this context means its validity cannot be established
927#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, Eq, Hash)]
928#[rasn(enumerated)]
929#[non_exhaustive]
930pub enum CertificateType {
931    Explicit = 0,
932    Implicit = 1,
933}
934
935/// This is a profile of the CertificateBase structure providing all
936///  the fields necessary for an implicit certificate, and no others.
937#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
938#[rasn(delegate)]
939pub struct ImplicitCertificate(CertificateBase);
940
941impl ImplicitCertificate {
942    pub fn new(data: CertificateBase) -> Result<Self, InnerSubtypeConstraintError> {
943        Self(data).validate_components()
944    }
945}
946impl InnerSubtypeConstraint for ImplicitCertificate {
947    fn validate_and_decode_containing(
948        self,
949        _: Option<rasn::Codec>,
950    ) -> Result<Self, rasn::error::InnerSubtypeConstraintError> {
951        if self.0.is_implicit() {
952            Ok(self)
953        } else {
954            Err(InnerSubtypeConstraintError::SubtypeConstraintViolation {
955                component_path: "ImplicitCertificate",
956                details: "CertificateBase is not implicit certificate",
957            })
958        }
959    }
960}
961
962impl core::ops::Deref for ImplicitCertificate {
963    type Target = CertificateBase;
964
965    fn deref(&self) -> &Self::Target {
966        &self.0
967    }
968    // We should not allow mutation of the inner data if they require validation!
969}
970
971/// This is a profile of the CertificateBase structure providing all the fields necessary for an explicit certificate, and no others.
972#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
973#[rasn(delegate)]
974pub struct ExplicitCertificate(CertificateBase);
975
976impl ExplicitCertificate {
977    pub fn new(data: CertificateBase) -> Result<Self, InnerSubtypeConstraintError> {
978        Self(data).validate_components()
979    }
980}
981
982impl InnerSubtypeConstraint for ExplicitCertificate {
983    fn validate_and_decode_containing(
984        self,
985        _: Option<rasn::Codec>,
986    ) -> Result<Self, rasn::error::InnerSubtypeConstraintError> {
987        if self.0.is_explicit() {
988            Ok(self)
989        } else {
990            Err(InnerSubtypeConstraintError::SubtypeConstraintViolation {
991                component_path: "ExplicitCertificate",
992                details: "CertificateBase is not explicit certificate",
993            })
994        }
995    }
996}
997impl core::ops::Deref for ExplicitCertificate {
998    type Target = CertificateBase;
999
1000    fn deref(&self) -> &Self::Target {
1001        &self.0
1002    }
1003    // We should not allow mutation of the inner data if they require validation!
1004}
1005
1006/// Allows certificate recipients to determine which keying material to use for
1007/// certificate authentication.
1008///
1009/// # Variants
1010/// ## `Sha256AndDigest`, `Sha384AndDigest`, `Sm3AndDigest`
1011/// - Contains `HashedId8` of issuing certificate
1012///   - Calculated with whole-certificate hash algorithm (per 6.4.3)
1013///   - Applied to COER-encoded, canonicalized certificate
1014/// - Hash algorithm for certificate verification:
1015///   - `Sha256AndDigest`: SHA-256
1016///   - `Sha384AndDigest`: SHA-384
1017///   - `Sm3AndDigest`: SM3
1018/// - Certificate verified with public key of indicated issuing certificate
1019///
1020/// ## `VSelf`
1021/// - Indicates hash algorithm for certificate verification
1022/// - Certificate verified with public key from `verifyKeyIndicator` in `ToBeSignedCertificate`
1023///
1024/// # Critical Information Field
1025/// This is a critical information field as defined in 5.2.5:
1026/// - An implementation that does not recognize the indicated CHOICE when verifying
1027///   a signed SPDU shall indicate that the SPDU is invalid (per 4.2.2.3.2)
1028/// - Invalid in this context means its validity cannot be established
1029#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1030#[rasn(choice, automatic_tags)]
1031#[non_exhaustive]
1032pub enum IssuerIdentifier {
1033    Sha256AndDigest(HashedId8),
1034    #[rasn(identifier = "self")]
1035    VSelf(HashAlgorithm),
1036    #[rasn(extension_addition)]
1037    Sha384AndDigest(HashedId8),
1038    #[rasn(extension_addition)]
1039    Sm3AndDigest(HashedId8),
1040}
1041
1042/// Certificate data to be signed, containing identification and permissions information.
1043///
1044/// This is summary. For the most accurate information, consult the source ASN.1 definitions.
1045///
1046/// # Hash Calculation
1047/// For both implicit and explicit certificates, hash is calculated as:
1048/// `Hash(Data input) || Hash(Signer identifier input)` where:
1049/// - Data input: COER encoding of toBeSigned (canonicalized)
1050/// - Signer identifier input depends on verification type:
1051///   - For self-signed (issuer is self): empty string
1052///   - For certificate: COER encoding of canonicalized issuer certificate
1053///
1054/// For implicit certificates, H(CertU) from SEC 4 is:
1055/// `H[H(canonicalized ToBeSignedCertificate) || H(issuer Certificate)]`
1056/// See 5.3.2 for differences from SEC 4 regarding hash-to-integer conversion.
1057///
1058/// # Fields
1059/// - `id`: Certificate holder identification
1060/// - `craca_id`: Certificate Revocation Authorization CA identifier
1061///   - HashedId3 calculated with whole-certificate hash algorithm (6.4.3)
1062/// - `crl_series`: CRL series for CRACA
1063/// - `validity_period`: Certificate validity period
1064/// - `region`: Validity region (if omitted):
1065///   - Self-signed: Valid worldwide
1066///   - Otherwise: Same as issuing certificate
1067/// - `assurance_level`: Certificate holder's assurance level
1068/// - `app_permissions`: Application data signing permissions
1069///   - Each Psid can appear at most once
1070/// - `cert_issue_permissions`: Certificate signing permissions
1071///   - At most one entry with "all" permissions
1072/// - `cert_request_permissions`: Certificate request permissions
1073///   - At most one entry with "all" permissions
1074/// - `can_request_rollover`: Permission to request same-permission certificate
1075///   - Reserved for future use
1076/// - `encryption_key`: Public encryption key
1077/// - `verify_key_indicator`: Public key recovery material
1078/// - `flags`: Additional properties
1079///   - `usesCubk`: Supports compact unified butterfly key response
1080///     - Only relevant for CA certificates
1081///     - Used only for certificate response consistency checks
1082/// - `app_extensions`: Additional application activity permissions
1083/// - `cert_issue_extensions`: Additional certificate issuing permissions
1084/// - `cert_request_extensions`: Additional certificate request permissions
1085///
1086/// # Canonicalization
1087/// Subject to canonicalization (6.1.2):
1088/// - Applies to `PublicEncryptionKey` and `VerificationKeyIndicator`
1089/// - Elliptic curve points must use compressed form (`compressed-y-0`/`compressed-y-1`)
1090///
1091/// # Critical Information Fields
1092/// ## App Permissions
1093/// - Critical field per 5.2.6
1094/// - Must support at least 8 entries
1095/// - Invalid SPDU if verification fails
1096///
1097/// ## Cert Issue Permissions
1098/// - Critical field per 5.2.6
1099/// - Must support at least 8 entries
1100/// - Invalid SPDU if CA certificate chain verification fails
1101///
1102/// ## Cert Request Permissions
1103/// - Critical field per 5.2.6
1104/// - Must support at least 8 entries
1105/// - Invalid SPDU if request verification fails
1106///
1107/// Implementation-specific behavior when non-relevant fields exceed supported size.
1108#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1109#[rasn(automatic_tags)]
1110#[non_exhaustive]
1111pub struct ToBeSignedCertificate {
1112    pub id: CertificateId,
1113    #[rasn(identifier = "cracaId")]
1114    pub craca_id: HashedId3,
1115    #[rasn(identifier = "crlSeries")]
1116    pub crl_series: CrlSeries,
1117    #[rasn(identifier = "validityPeriod")]
1118    pub validity_period: ValidityPeriod,
1119    pub region: Option<GeographicRegion>,
1120    #[rasn(identifier = "assuranceLevel")]
1121    pub assurance_level: Option<SubjectAssurance>,
1122    #[rasn(identifier = "appPermissions")]
1123    pub app_permissions: Option<SequenceOfPsidSsp>,
1124    #[rasn(identifier = "certIssuePermissions")]
1125    pub cert_issue_permissions: Option<SequenceOfPsidGroupPermissions>,
1126    #[rasn(identifier = "certRequestPermissions")]
1127    pub cert_request_permissions: Option<SequenceOfPsidGroupPermissions>,
1128    #[rasn(identifier = "canRequestRollover")]
1129    pub can_request_rollover: Option<()>,
1130    #[rasn(identifier = "encryptionKey")]
1131    pub encryption_key: Option<PublicEncryptionKey>,
1132    #[rasn(identifier = "verifyKeyIndicator")]
1133    pub verify_key_indicator: VerificationKeyIndicator,
1134    #[rasn(extension_addition)]
1135    pub flags: Option<FixedBitString<8>>,
1136    #[rasn(extension_addition, identifier = "appExtensions")]
1137    pub app_extensions: Option<SequenceOfAppExtensions>,
1138    #[rasn(extension_addition, identifier = "certIssueExtensions")]
1139    pub cert_issue_extensions: Option<SequenceOfCertIssueExtensions>,
1140    #[rasn(extension_addition, identifier = "certRequestExtension")]
1141    pub cert_request_extension: Option<SequenceOfCertRequestExtensions>,
1142}
1143#[bon::bon]
1144impl ToBeSignedCertificate {
1145    #[builder]
1146    pub fn new(
1147        id: CertificateId,
1148        craca_id: HashedId3,
1149        crl_series: CrlSeries,
1150        validity_period: ValidityPeriod,
1151        region: Option<GeographicRegion>,
1152        assurance_level: Option<SubjectAssurance>,
1153        app_permissions: Option<SequenceOfPsidSsp>,
1154        cert_issue_permissions: Option<SequenceOfPsidGroupPermissions>,
1155        cert_request_permissions: Option<SequenceOfPsidGroupPermissions>,
1156        can_request_rollover: Option<()>,
1157        encryption_key: Option<PublicEncryptionKey>,
1158        verify_key_indicator: VerificationKeyIndicator,
1159        flags: Option<FixedBitString<8>>,
1160        app_extensions: Option<SequenceOfAppExtensions>,
1161        cert_issue_extensions: Option<SequenceOfCertIssueExtensions>,
1162        cert_request_extension: Option<SequenceOfCertRequestExtensions>,
1163    ) -> Result<Self, InnerSubtypeConstraintError> {
1164        let cert = Self {
1165            id,
1166            craca_id,
1167            crl_series,
1168            validity_period,
1169            region,
1170            assurance_level,
1171            app_permissions,
1172            cert_issue_permissions,
1173            cert_request_permissions,
1174            can_request_rollover,
1175            encryption_key,
1176            verify_key_indicator,
1177            flags,
1178            app_extensions,
1179            cert_issue_extensions,
1180            cert_request_extension,
1181        };
1182        cert.validate_components()
1183    }
1184}
1185
1186impl InnerSubtypeConstraint for ToBeSignedCertificate {
1187    fn validate_and_decode_containing(
1188        self,
1189        _: Option<rasn::Codec>,
1190    ) -> Result<Self, rasn::error::InnerSubtypeConstraintError> {
1191        if self.app_permissions.is_none()
1192            && self.cert_issue_permissions.is_none()
1193            && self.cert_request_permissions.is_none()
1194        {
1195            return Err(InnerSubtypeConstraintError::MissingRequiredComponent {
1196                component_path: "ToBeSignedCertificate",
1197                components: &[
1198                    "app_permissions",
1199                    "cert_issue_permissions",
1200                    "cert_request_permissions",
1201                ],
1202            });
1203        }
1204        Ok(self)
1205    }
1206}
1207
1208/// Contains information to identify the certificate holder when necessary.
1209///
1210/// # Variants
1211/// - `LinkageData`: Identifies certificate for revocation in linked certificate CRLs
1212///   (See sections 5.1.3 and 7.3 for details)
1213///
1214/// - `Name`: Identifies non-anonymous certificate holders
1215///   - Contents are policy-dependent and expected to be human-readable
1216///
1217/// - `BinaryId`: Supports non-human-readable identifiers
1218///
1219/// - `None`: Indicates certificate does not include an identifier
1220///
1221/// # Critical Information Field
1222/// This is a critical information field as defined in 5.2.6:
1223/// - An implementation that does not recognize the indicated CHOICE shall
1224///   reject the signed SPDU as invalid
1225#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1226#[rasn(choice, automatic_tags)]
1227#[non_exhaustive]
1228pub enum CertificateId {
1229    LinkageData(LinkageData),
1230    Name(Hostname),
1231    #[rasn(size("1..=64"))]
1232    BinaryId(OctetString),
1233    None(()),
1234}
1235
1236/// Contains information for matching against linkage ID-based CRLs to determine
1237/// certificate revocation status.
1238///
1239/// See sections 5.1.3.4 and 7.3 for detailed usage information.
1240#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1241#[rasn(automatic_tags)]
1242pub struct LinkageData {
1243    #[rasn(identifier = "iCert")]
1244    pub i_cert: IValue,
1245    #[rasn(identifier = "linkage-value")]
1246    pub linkage_value: LinkageValue,
1247    #[rasn(identifier = "group-linkage-value")]
1248    pub group_linkage_value: Option<GroupLinkageValue>,
1249}
1250
1251/// Indicates permitted permission types in end-entity certificates whose permission
1252/// chain passes through this `PsidGroupPermissions` field.
1253///
1254/// # Variants
1255/// - `App`: End-entity certificate may contain `appPermissions` field
1256/// - `Enroll`: End-entity certificate may contain `certRequestPermissions` field
1257/// # Note
1258/// BIT STRING {app (0), enrol (1) } (SIZE (8)) (ALL EXCEPT {})
1259#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1260#[rasn(delegate, size(8))]
1261pub struct EndEntityType(pub FixedBitString<8usize>);
1262
1263/// When initializing `EndEntityType`, use the following constants as the first byte for `FixedBitString<8>`.
1264impl EndEntityType {
1265    pub const APP: u8 = 0b1000_0000;
1266    pub const ENROLL: u8 = 0b0100_0000;
1267    pub const BOTH: u8 = 0b1100_0000;
1268}
1269
1270delegate!(FixedBitString<8>, EndEntityType);
1271
1272/// Specifies permissions for certificate issuance and requests for a set of PSIDs.
1273/// See examples in D.5.3 and D.5.4.
1274///
1275/// # Fields
1276/// - `subject_permissions`: PSIDs and SSP Ranges covered
1277///
1278/// - `min_chain_length` and `chain_length_range`: Permitted certificate chain length
1279///   - Chain length: Number of certificates below this one, including end-entity
1280///   - Permitted length: `min_chain_length` to `min_chain_length + chain_length_range`
1281///   - Special cases:
1282///     - `min_chain_length` of 0 not allowed in `certIssuePermissions`
1283///     - `chain_length_range` of -1 allows any length ≥ `min_chain_length`
1284///
1285/// - `ee_type`: Types of certificates/requests this permission authorizes
1286///   - `app`: Allows chain to end in authorization certificate
1287///   - `enroll`: Allows chain to end in enrollment certificate
1288///   - Different `PsidGroupPermissions` instances may have different `ee_type` values
1289///
1290/// # Validation Rules
1291/// - Chain ending in authorization certificate requires `app` in `ee_type`
1292/// - Chain ending in enrollment certificate requires `enroll` in `ee_type`
1293/// - Invalid chain if end certificate type doesn't match `ee_type`
1294#[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1295#[rasn(automatic_tags)]
1296pub struct PsidGroupPermissions {
1297    #[rasn(identifier = "subjectPermissions")]
1298    pub subject_permissions: SubjectPermissions,
1299    #[rasn(
1300        default = "psid_group_permissions_min_chain_length_default",
1301        identifier = "minChainLength"
1302    )]
1303    #[builder(default = psid_group_permissions_min_chain_length_default())]
1304    pub min_chain_length: Integer,
1305    #[rasn(
1306        default = "psid_group_permissions_chain_length_range_default",
1307        identifier = "chainLengthRange"
1308    )]
1309    #[builder(default = psid_group_permissions_chain_length_range_default())]
1310    pub chain_length_range: Integer,
1311    #[rasn(
1312        default = "psid_group_permissions_ee_type_default",
1313        identifier = "eeType"
1314    )]
1315    #[builder(default = psid_group_permissions_ee_type_default())]
1316    pub ee_type: EndEntityType,
1317}
1318
1319fn psid_group_permissions_min_chain_length_default() -> Integer {
1320    Integer::from(1)
1321}
1322fn psid_group_permissions_chain_length_range_default() -> Integer {
1323    Integer::from(0)
1324}
1325fn psid_group_permissions_ee_type_default() -> EndEntityType {
1326    // First byte holds the bits, container is larger than needed
1327    EndEntityType(FixedBitString::new([
1328        EndEntityType::APP,
1329        0,
1330        0,
1331        0,
1332        0,
1333        0,
1334        0,
1335        0,
1336    ]))
1337}
1338
1339/// This type is used for clarity of definitions.
1340#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1341#[rasn(delegate)]
1342pub struct SequenceOfPsidGroupPermissions(pub SequenceOf<PsidGroupPermissions>);
1343
1344delegate!(
1345    SequenceOf<PsidGroupPermissions>,
1346    SequenceOfPsidGroupPermissions
1347);
1348
1349/// Indicates PSIDs and associated SSPs for certificate issuance or request
1350/// permissions granted by a `PsidGroupPermissions` structure.
1351///
1352/// # Variants
1353/// - `Explicit`: Grants permissions for specific PSIDs and SSP Ranges
1354/// - `All`: Grants permissions for all PSIDs not covered by other
1355///   `PsidGroupPermissions` in the same `certIssuePermissions` or
1356///   `certRequestPermissions` field
1357///
1358/// # Critical Information Fields
1359/// This is a critical information field as defined in 5.2.6:
1360/// - Implementation must recognize the indicated CHOICE when verifying SPDU
1361/// - For `Explicit` variant:
1362///   - Must support at least 8 entries in `PsidSspRange`
1363///   - Implementation must support specified number of entries
1364/// - Invalid SPDU (per 4.2.2.3.2) if:
1365///   - CHOICE is not recognized
1366///   - Number of entries in `Explicit` variant exceeds implementation support
1367///
1368/// Invalid in this context means validity cannot be established.
1369#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1370#[rasn(choice, automatic_tags)]
1371#[non_exhaustive]
1372pub enum SubjectPermissions {
1373    Explicit(SequenceOfPsidSspRange),
1374    All(()),
1375}
1376
1377/// Contains either verification key or reconstruction value depending on certificate type.
1378///
1379/// # Variants
1380/// - `VerificationKey`: For explicit certificates
1381///   - Contains public key for verifying holder's signatures
1382///
1383/// - `ReconstructionValue`: For implicit certificates
1384///   - Contains value for recovering public key (per SEC 4 and 5.3.2)
1385///
1386/// # Critical Information Field
1387/// This is a critical information field as defined in 5.2.5:
1388/// - An implementation that does not recognize the indicated CHOICE when verifying
1389///   a signed SPDU shall indicate that the SPDU is invalid (per 4.2.2.3.2)
1390/// - Invalid in this context means its validity cannot be established
1391///
1392/// # Canonicalization
1393/// Subject to canonicalization for operations specified in 6.1.2:
1394/// - Applies to `PublicVerificationKey` and `EccP256CurvePoint`
1395/// - `EccP256CurvePoint` must be in compressed form:
1396///   - Choice must be either `compressed-y-0` or `compressed-y-1`
1397#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1398#[rasn(choice, automatic_tags)]
1399#[non_exhaustive]
1400pub enum VerificationKeyIndicator {
1401    VerificationKey(PublicVerificationKey),
1402    ReconstructionValue(EccP256CurvePoint),
1403}
1404
1405/// Represents an individual `AppExtension`.
1406///
1407/// Extensions are drawn from the ASN.1 Information Object Set `SetCertExtensions`.
1408/// Each `AppExtension` is associated with a `CertIssueExtension` and a
1409/// `CertRequestExtension`, all identified by the same `id` value.
1410///
1411/// # Fields
1412/// - `id`: Identifies the extension type
1413/// - `content`: Provides the content of the extension
1414#[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
1415#[rasn(automatic_tags)]
1416pub struct AppExtension<T: CertExtType> {
1417    pub id: ExtId,
1418    pub content: T::App,
1419}
1420
1421/// Contains `CertRequestExtensions` that apply to the certificate holder.
1422///
1423/// # Consistency Requirements
1424/// As specified in 5.2.4.2.3, each `CertRequestExtension` type has specific
1425/// consistency conditions governing:
1426/// - Consistency with `AppExtensions` in certificates issued by the holder
1427/// - Consistency with `CertRequestExtensions` in CA certificates in the holder's chain
1428///
1429/// See individual `CertRequestExtension` definitions for their specific
1430/// consistency conditions.
1431#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1432#[rasn(delegate, size("1.."))]
1433pub struct SequenceOfCertIssueExtensions(pub SequenceOf<OperatingOrganizationIssueExtension>);
1434
1435delegate!(
1436    SequenceOf<OperatingOrganizationIssueExtension>,
1437    SequenceOfCertIssueExtensions
1438);
1439
1440#[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
1441#[rasn(choice, automatic_tags)]
1442pub enum IssuePermissions<T: CertExtType> {
1443    #[rasn(identifier = "specific")]
1444    Specific(T::Issue),
1445    #[rasn(identifier = "all")]
1446    All(()),
1447}
1448
1449/// Represents an individual `CertIssueExtension`.
1450///
1451/// Extensions are drawn from the ASN.1 Information Object Set `SetCertExtensions`.
1452/// Each `CertIssueExtension` is associated with an `AppExtension` and a
1453/// `CertRequestExtension`, all identified by the same `id` value.
1454///
1455/// # Fields
1456/// - `id`: Identifies the extension type
1457///
1458/// - `permissions`: Indicates the permissions
1459///   - `All`: Certificate is entitled to issue all values of the extension
1460///   - `Specific`: Specifies which extension values may be issued when `All` doesn't apply
1461#[derive(Builder, AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
1462#[rasn(automatic_tags)]
1463pub struct CertIssueExtension<T: CertExtType> {
1464    pub id: ExtId,
1465    pub permissions: IssuePermissions<T>,
1466}
1467impl<T: CertExtType> CertIssueExtension<T> {
1468    pub fn new_specific(permissions: T::Issue) -> Self {
1469        Self {
1470            id: T::ID,
1471            permissions: IssuePermissions::Specific(permissions),
1472        }
1473    }
1474    pub fn new_all() -> Self {
1475        Self {
1476            id: T::ID,
1477            permissions: IssuePermissions::All(()),
1478        }
1479    }
1480}
1481
1482/// Contains `CertRequestExtensions` that apply to the certificate holder.
1483///
1484/// # Consistency Requirements
1485/// As specified in 5.2.4.2.3, each `CertRequestExtension` type has specific
1486/// consistency conditions governing:
1487/// - Consistency with `AppExtensions` in certificates issued by the holder
1488/// - Consistency with `CertRequestExtensions` in CA certificates in the holder's chain
1489///
1490/// See individual `CertRequestExtension` definitions for their specific
1491/// consistency conditions.
1492#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1493#[rasn(delegate, size("1.."))]
1494pub struct SequenceOfCertRequestExtensions(pub SequenceOf<OperatingOrganizationRequestExtension>);
1495
1496delegate!(
1497    SequenceOf<OperatingOrganizationRequestExtension>,
1498    SequenceOfCertRequestExtensions
1499);
1500
1501#[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
1502#[rasn(choice, automatic_tags)]
1503pub enum RequestPermissions<T: CertExtType> {
1504    #[rasn(identifier = "content")]
1505    Content(T::Req),
1506    #[rasn(identifier = "all")]
1507    All(()),
1508}
1509
1510/// Represents an individual `CertRequestExtension`.
1511///
1512/// Extensions are drawn from the ASN.1 Information Object Set `SetCertExtensions`.
1513/// Each `CertRequestExtension` is associated with an `AppExtension` and a
1514/// `CertRequestExtension`, all identified by the same `id` value.
1515///
1516/// # Fields
1517/// - `id`: Identifies the extension type
1518///
1519/// - `permissions`: Indicates the permissions
1520///   - `All`: Certificate is entitled to issue all values of the extension
1521///   - `Specific`: Specifies which extension values may be issued when `All` doesn't apply
1522#[derive(Builder, AsnType, Debug, Encode, Decode, Clone, PartialEq, Eq, Hash)]
1523#[rasn(automatic_tags)]
1524pub struct CertRequestExtension<T: CertExtType> {
1525    pub id: ExtId,
1526    pub permissions: RequestPermissions<T>,
1527}
1528
1529/// AppExtension used to identify an operating organization. Both associated
1530/// `CertIssueExtension` and `CertRequestExtension` are of type `OperatingOrganizationId`.
1531///
1532/// # SPDU Consistency
1533/// SDEE specification for the SPDU must specify how to determine an OBJECT
1534/// IDENTIFIER, either by:
1535/// - Including the full OBJECT IDENTIFIER in the SPDU
1536/// - Including a RELATIVE-OID with instructions for obtaining full OBJECT IDENTIFIER
1537///
1538/// SPDU is consistent if its determined OBJECT IDENTIFIER matches this field's value.
1539///
1540/// # Extension Properties
1541/// - No consistency conditions with corresponding `CertIssueExtension`
1542/// - Can appear in certificates issued by any CA
1543#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1544#[rasn(delegate)]
1545pub struct OperatingOrganizationId(pub ObjectIdentifier);
1546
1547delegate!(ObjectIdentifier, OperatingOrganizationId);
1548
1549#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1550pub struct OperatingOrganizationExtension;
1551
1552impl CertExtType for OperatingOrganizationExtension {
1553    type App = OperatingOrganizationId;
1554    type Issue = (); // NULL in ASN.1
1555    type Req = (); // NULL in ASN.1
1556    const ID: ExtId = CERT_EXT_ID_OPERATING_ORGANIZATION;
1557}
1558
1559pub type OperatingOrganizationAppExtension = AppExtension<OperatingOrganizationExtension>;
1560pub type OperatingOrganizationIssueExtension = CertIssueExtension<OperatingOrganizationExtension>;
1561pub type OperatingOrganizationRequestExtension =
1562    CertRequestExtension<OperatingOrganizationExtension>;
1563
1564#[derive(Debug, Clone, PartialEq, Eq)]
1565#[non_exhaustive]
1566pub enum SetCertExtensionsType {
1567    OperatingOrganization(OperatingOrganizationExtension),
1568}
1569
1570/// Contains `AppExtensions` that apply to the certificate holder.
1571///
1572/// # Consistency Requirements
1573/// As specified in 5.2.4.2.3, each `AppExtension` type has specific
1574/// consistency conditions governing:
1575/// - Consistency with SPDUs signed by the holder
1576/// - Consistency with `CertIssueExtensions` in CA certificates in the holder's chain
1577/// # Note
1578/// See individual `AppExtension` definitions for their specific
1579/// consistency conditions.
1580#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1581#[rasn(delegate, size("1.."))]
1582pub struct SequenceOfAppExtensions(pub SequenceOf<OperatingOrganizationAppExtension>);
1583
1584delegate!(
1585    SequenceOf<OperatingOrganizationAppExtension>,
1586    SequenceOfAppExtensions
1587);
1588
1589/// --                     IEEE Std 1609.2: CRL Data Types                       --
1590pub mod crl {
1591    extern crate alloc;
1592    use super::base_types::{Psid, Uint8};
1593    use super::crl_base_types::CrlContents;
1594    use super::{
1595        CrlSeries, HeaderInfo, Ieee1609Dot2Content, Ieee1609Dot2Data, SignedData,
1596        SignedDataPayload, ToBeSignedData,
1597    };
1598    use crate::delegate;
1599    use bon::Builder;
1600    use rasn::error::InnerSubtypeConstraintError;
1601    use rasn::prelude::*;
1602
1603    /// This is the PSID for the CRL application.
1604    #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1605    #[rasn(delegate, value("256"))]
1606    pub struct CrlPsid(Psid);
1607
1608    impl CrlPsid {
1609        pub const CRL_PSID: u16 = 256;
1610        pub fn new() -> Self {
1611            Self(Psid(Integer::from(Self::CRL_PSID)))
1612        }
1613    }
1614    impl Default for CrlPsid {
1615        fn default() -> Self {
1616            Self::new()
1617        }
1618    }
1619    delegate!(Psid, CrlPsid);
1620
1621    /// This structure is the SPDU used to contain a signed CRL. A valid signed CRL meets the validity criteria of 7.4."]
1622    #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1623    #[rasn(delegate)]
1624    pub struct SecuredCrl(Ieee1609Dot2Data);
1625
1626    impl InnerSubtypeConstraint for SecuredCrl {
1627        /// Validates that the `Ieee1609Dot2Data` contains a valid CRL SPDU. Optionally checks interal bytes for `CrlContents` based on the given codec.
1628        fn validate_and_decode_containing(
1629            self,
1630            decode_containing_with: Option<rasn::Codec>,
1631        ) -> Result<Self, rasn::error::InnerSubtypeConstraintError> {
1632            let signed_data_content;
1633            if let Ieee1609Dot2Data {
1634                content: Ieee1609Dot2Content::SignedData(signed_data),
1635                ..
1636            } = &self.0
1637            {
1638                signed_data_content = &**signed_data;
1639            } else {
1640                return Err(InnerSubtypeConstraintError::MissingRequiredComponent {
1641                    component_path: "Ieee1609Dot2Data.content",
1642                    components: &["Ieee1609Dot2Content::SignedData"],
1643                });
1644            }
1645            let crl_psid = CrlPsid::default();
1646            if matches!(
1647                signed_data_content,
1648                SignedData {
1649                    tbs_data: ToBeSignedData {
1650                        payload: SignedDataPayload {
1651                            data: Some(Ieee1609Dot2Data {
1652                                protocol_version: _,
1653                                content: Ieee1609Dot2Content::UnsecuredData(_)
1654                            }),
1655                            ..
1656                        },
1657                        header_info: HeaderInfo {
1658                            psid: _,
1659                            generation_time: None,
1660                            expiry_time: None,
1661                            generation_location: None,
1662                            p2pcd_learning_request: None,
1663                            missing_crl_identifier: None,
1664                            encryption_key: None,
1665                            ..
1666                        },
1667                    },
1668                    ..
1669                }
1670            ) {
1671                if let Some(codec) = decode_containing_with {
1672                    let inner_unsecured_data = signed_data_content
1673                        .tbs_data
1674                        .payload
1675                        .data
1676                        .as_ref()
1677                        .and_then(|data| {
1678                            if let Ieee1609Dot2Data {
1679                                content: Ieee1609Dot2Content::UnsecuredData(inner_data),
1680                                ..
1681                            } = data
1682                            {
1683                                Some(inner_data)
1684                            } else {
1685                                None
1686                            }
1687                        });
1688                    if let Some(inner_unsecured_data) = inner_unsecured_data {
1689                        let decoded = codec.decode_from_binary::<CrlContents>(inner_unsecured_data);
1690                        match decoded {
1691                            Ok(_) => return Ok(self),
1692                            Err(err) => {
1693                                return Err(InnerSubtypeConstraintError::InvalidInnerContaining {
1694                                    expected: "CrlContents",
1695                                    err,
1696                                });
1697                            }
1698                        }
1699                    }
1700                    // Should be unreachable (UnsecuredData presence already checked)
1701                    debug_assert!(false);
1702                }
1703                Ok(self)
1704            } else if signed_data_content.tbs_data.header_info.psid == *crl_psid {
1705                Err(InnerSubtypeConstraintError::InvalidComponentValue {
1706                    component_path: "Ieee1609Dot2Data.content.signedData.tbsData.headerInfo",
1707                    component_name: "psid",
1708                    details: alloc::format!(
1709                        "Expecting Psid value {} for SecuredCrl",
1710                        CrlPsid::CRL_PSID
1711                    ),
1712                })
1713            } else {
1714                Err(InnerSubtypeConstraintError::SubtypeConstraintViolation {
1715                    component_path: "Ieee1609Dot2Data.content.signedData",
1716                    details: "SignedData does not contain a valid CRL SPDU",
1717                })
1718            }
1719        }
1720    }
1721    /// Service Specific Permissions (SSP) structure for Certificate Revocation List (CRL) signing.
1722    ///
1723    /// # Fields
1724    ///
1725    /// * `version` - The version number of the SSP. Must be 1 for this version.
1726    ///
1727    /// * `associated_craca` - Identifies the relationship between this certificate and
1728    ///   the Certificate Revocation Authorization CA (CRACA):
1729    ///   - If `IsCraca`: This certificate is the CRACA certificate and signs CRLs for
1730    ///     certificates which chain back to this certificate
1731    ///   - If `IssuerIsCraca`: The issuer of this certificate is the CRACA and this
1732    ///     certificate may sign CRLs for certificates which chain back to its issuer
1733    ///
1734    /// * `crls` - Identifies what type of CRLs may be issued by the certificate holder.
1735    #[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq)]
1736    #[rasn(automatic_tags)]
1737    #[non_exhaustive]
1738    pub struct CrlSsp {
1739        #[rasn(value("1"))]
1740        #[builder(default = CrlSsp::VERSION)]
1741        #[rasn(identifier = "version")]
1742        pub version: Uint8,
1743        #[rasn(identifier = "associatedCraca")]
1744        pub associated_craca: CracaType,
1745        #[rasn(identifier = "crls")]
1746        pub crls: PermissibleCrls,
1747    }
1748    impl CrlSsp {
1749        pub const VERSION: u8 = 1;
1750    }
1751
1752    /// Type used to determine the validity of the `crl_craca` field in the `CrlContents` structure.
1753    ///
1754    /// # Values
1755    ///
1756    /// * `IsCraca` - The `crl_craca` field in `CrlContents` is only valid if it indicates
1757    ///   the certificate that signs the CRL.
1758    ///
1759    /// * `IssuerIsCraca` - The `crl_craca` field in `CrlContents` is only valid if it indicates
1760    ///   the certificate that issued the certificate that signs the CRL.
1761    #[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, Eq)]
1762    #[rasn(enumerated)]
1763    pub enum CracaType {
1764        IsCraca,
1765        IssuerIsCraca,
1766    }
1767
1768    /// This type is used to determine the validity of the crlSeries field
1769    /// in the CrlContents structure.
1770    ///
1771    /// The crlSeries field in the CrlContents structure is invalid unless that value appears as an entry in the SEQUENCE contained in this field.
1772    #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1773    #[rasn(delegate)]
1774    pub struct PermissibleCrls(pub SequenceOf<CrlSeries>);
1775
1776    delegate!(SequenceOf<CrlSeries>, PermissibleCrls);
1777}
1778/// --           IEEE Std 1609.2: Peer-to-Peer Distribution Data Types           --
1779pub mod peer2peer {
1780    use super::Certificate;
1781    use super::base_types::Uint8;
1782    use crate::delegate;
1783    use bon::Builder;
1784    use rasn::prelude::*;
1785    /// A Peer-to-Peer PDU structure for IEEE 1609.2 certificate chain responses.
1786    ///
1787    /// # Fields
1788    ///
1789    /// * `version` - The version number of this structure. Must be 1 for this version
1790    ///   of the standard.
1791    ///
1792    /// * `content` - Contains the certificate chain response:
1793    ///   - When `CaCerts` variant is used, it contains an array of certificates where:
1794    ///     - Each certificate is issued by the next certificate in the array
1795    ///     - The first certificate matches the one indicated by the `p2pcd_learning_request`
1796    ///       MCI value in the request message (see 8.4.2)
1797    ///     - The final certificate in the array was issued by a root CA
1798    #[derive(Builder, AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq)]
1799    #[rasn(automatic_tags)]
1800    #[non_exhaustive]
1801    pub struct Ieee1609Dot2Peer2PeerPDU {
1802        #[rasn(value("1"))]
1803        #[builder(default = Ieee1609Dot2Peer2PeerPDU::VERSION)]
1804        #[rasn(identifier = "version")]
1805        pub version: Uint8,
1806        #[rasn(identifier = "content")]
1807        pub content: Ieee1609Dot2Peer2PeerPduContent,
1808    }
1809    impl Ieee1609Dot2Peer2PeerPDU {
1810        pub const VERSION: u8 = 1;
1811    }
1812
1813    /// Content types for Peer-to-Peer PDU.
1814    #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq)]
1815    #[rasn(choice, automatic_tags)]
1816    #[non_exhaustive]
1817    pub enum Ieee1609Dot2Peer2PeerPduContent {
1818        #[rasn(identifier = "caCerts")]
1819        CaCerts(CaCertP2pPDU),
1820    }
1821
1822    /// This type is used for clarity of definitions.
1823    #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]
1824    #[rasn(delegate)]
1825    pub struct CaCertP2pPDU(pub SequenceOf<Certificate>);
1826
1827    delegate!(SequenceOf<Certificate>, CaCertP2pPDU);
1828}
1829
1830#[cfg(test)]
1831mod tests {
1832    use super::*;
1833    macro_rules! round_trip {
1834        ($codec:ident, $typ:ty, $value:expr, $expected:expr) => {{
1835            let value: $typ = $value;
1836            let expected: &[u8] = $expected;
1837            let actual_encoding = rasn::$codec::encode(&value).unwrap();
1838            // dbg!(&actual_encoding);
1839
1840            pretty_assertions::assert_eq!(&*actual_encoding, expected);
1841
1842            let decoded_value = rasn::$codec::decode::<$typ>(&actual_encoding);
1843            match decoded_value {
1844                Ok(decoded) => {
1845                    pretty_assertions::assert_eq!(value, decoded);
1846                }
1847                Err(err) => {
1848                    panic!("{:?}", err);
1849                }
1850            }
1851        }};
1852    }
1853
1854    #[test]
1855    fn test_signed_data_payload() {
1856        let payload_data = SignedDataPayload::builder()
1857            .data(
1858                Ieee1609Dot2Data::builder()
1859                    .protocol_version(3)
1860                    .content(Ieee1609Dot2Content::UnsecuredData(
1861                        OctetString::from("This is a BSM\r\n".as_bytes()).into(),
1862                    ))
1863                    .build(),
1864            )
1865            .build()
1866            .unwrap();
1867        round_trip!(
1868            coer,
1869            SignedDataPayload,
1870            payload_data,
1871            // 0x40, 0x03, 0x80, 0x0F, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x42, 0x53, 0x4D, 0x0D, 0x0A
1872            &[
1873                64, 3, 128, 15, 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 66, 83, 77, 13, 10
1874            ]
1875        );
1876    }
1877    #[test]
1878    fn test_ieee_basic_safety_message() {
1879        let ieee1609dot2data: Ieee1609Dot2Data = Ieee1609Dot2Data::builder()
1880            .protocol_version(3)
1881            .content(Ieee1609Dot2Content::SignedData(Box::new(
1882                SignedData::builder()
1883                    .hash_id(HashAlgorithm::Sha256)
1884                    .tbs_data(
1885                        ToBeSignedData::builder()
1886                            .payload(
1887                                SignedDataPayload::builder()
1888                                    .data(
1889                                        Ieee1609Dot2Data::builder()
1890                                            .protocol_version(3)
1891                                            .content(Ieee1609Dot2Content::UnsecuredData(
1892                                                OctetString::from("This is a BSM\r\n".as_bytes())
1893                                                    .into(),
1894                                            ))
1895                                            .build(),
1896                                    )
1897                                    .build()
1898                                    .unwrap(),
1899                            )
1900                            .header_info(
1901                                HeaderInfo::builder()
1902                                    .psid(Integer::from(32).into())
1903                                    .generation_time(1_230_066_625_199_609_624.into())
1904                                    .build(),
1905                            )
1906                            .build(),
1907                    )
1908                    .signer(SignerIdentifier::Digest(HashedId8(
1909                        "!\"#$%&'(".as_bytes().try_into().unwrap(),
1910                    )))
1911                    .signature(Signature::EcdsaNistP256(
1912                        EcdsaP256Signature::builder()
1913                            .r_sig(EccP256CurvePoint::CompressedY0(
1914                                b"12345678123456781234567812345678"
1915                                    .to_vec()
1916                                    .try_into()
1917                                    .unwrap(),
1918                            ))
1919                            .s_sig(
1920                                b"ABCDEFGHABCDEFGHABCDEFGHABCDEFGH"
1921                                    .to_vec()
1922                                    .try_into()
1923                                    .unwrap(),
1924                            )
1925                            .build(),
1926                    ))
1927                    .build(),
1928            )))
1929            .build();
1930
1931        round_trip!(
1932            coer,
1933            Ieee1609Dot2Data,
1934            ieee1609dot2data,
1935            &[
1936                0x03, 0x81, 0x00, 0x40, 0x03, 0x80, 0x0F, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
1937                0x20, 0x61, 0x20, 0x42, 0x53, 0x4D, 0x0D, 0x0A, 0x40, 0x01, 0x20, 0x11, 0x12, 0x13,
1938                0x14, 0x15, 0x16, 0x17, 0x18, 0x80, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
1939                0x80, 0x82, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34,
1940                0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32,
1941                0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
1942                0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
1943                0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
1944            ]
1945        );
1946    }
1947    #[test]
1948    fn test_bsm_with_cert() {
1949        round_trip!(
1950            coer,
1951            Ieee1609Dot2Data,
1952            Ieee1609Dot2Data::builder()
1953                .protocol_version(3)
1954                .content(Ieee1609Dot2Content::SignedData(Box::new(
1955                    SignedData::builder()
1956                        .hash_id(HashAlgorithm::Sha256)
1957                        .tbs_data(
1958                            ToBeSignedData::builder()
1959                                .payload(
1960                                    SignedDataPayload::builder()
1961                                        .data(
1962                                            Ieee1609Dot2Data::builder()
1963                                                .protocol_version(3)
1964                                                .content(Ieee1609Dot2Content::UnsecuredData(
1965                                                    Opaque("This is a BSM\r\n".as_bytes().into())
1966                                                ))
1967                                                .build(),
1968                                        )
1969                                        .build()
1970                                        .unwrap(),
1971                                )
1972                                .header_info(
1973                                    HeaderInfo::builder()
1974                                        .psid(Integer::from(32).into())
1975                                        .generation_time(1_230_066_625_199_609_624.into())
1976                                        .build(),
1977                                )
1978                                .build()
1979                        )
1980                        .signer(SignerIdentifier::Certificate(
1981                            vec![Certificate::from(
1982                                ImplicitCertificate::new(
1983                                    CertificateBase::builder()
1984                                        .version(3)
1985                                        .r#type(CertificateType::Implicit)
1986                                        .issuer(IssuerIdentifier::Sha256AndDigest(HashedId8(
1987                                            "!\"#$%&'(".as_bytes().try_into().unwrap()
1988                                        )))
1989                                        .to_be_signed(
1990                                            ToBeSignedCertificate::builder()
1991                                                .id(CertificateId::LinkageData(
1992                                                    LinkageData::builder()
1993                                                        .i_cert(IValue::from(100))
1994                                                        .linkage_value(LinkageValue(
1995                                                            FixedOctetString::try_from(
1996                                                                b"123456789".as_slice()
1997                                                            )
1998                                                            .unwrap()
1999                                                        ))
2000                                                        .group_linkage_value(
2001                                                            GroupLinkageValue::builder()
2002                                                                .j_value(
2003                                                                    b"ABCD"
2004                                                                        .as_slice()
2005                                                                        .try_into()
2006                                                                        .unwrap()
2007                                                                )
2008                                                                .value(
2009                                                                    b"QRSTUVWXY"
2010                                                                        .as_slice()
2011                                                                        .try_into()
2012                                                                        .unwrap()
2013                                                                )
2014                                                                .build()
2015                                                        )
2016                                                        .build()
2017                                                ))
2018                                                .craca_id(HashedId3(
2019                                                    b"abc".as_slice().try_into().unwrap()
2020                                                ))
2021                                                .crl_series(CrlSeries::from(70))
2022                                                .validity_period(
2023                                                    ValidityPeriod::builder()
2024                                                        .start(81_828_384.into())
2025                                                        .duration(Duration::Hours(169))
2026                                                        .build()
2027                                                )
2028                                                .region(GeographicRegion::IdentifiedRegion(
2029                                                    vec![
2030                                                        IdentifiedRegion::CountryOnly(
2031                                                            UnCountryId::from(124)
2032                                                        ),
2033                                                        IdentifiedRegion::CountryOnly(
2034                                                            UnCountryId::from(484)
2035                                                        ),
2036                                                        IdentifiedRegion::CountryOnly(
2037                                                            UnCountryId::from(840)
2038                                                        )
2039                                                    ]
2040                                                    .into()
2041                                                ))
2042                                                .app_permissions(
2043                                                    vec![
2044                                                        PsidSsp {
2045                                                            psid: Integer::from(32).into(),
2046                                                            ssp: None
2047                                                        },
2048                                                        PsidSsp {
2049                                                            psid: Integer::from(38).into(),
2050                                                            ssp: None
2051                                                        }
2052                                                    ]
2053                                                    .into()
2054                                                )
2055                                                .verify_key_indicator(
2056                                                    VerificationKeyIndicator::ReconstructionValue(
2057                                                        EccP256CurvePoint::CompressedY0(
2058                                                            FixedOctetString::from([
2059                                                                0x91u8, 0x92, 0x93, 0x94, 0x95,
2060                                                                0x96, 0x97, 0x98, 0x91, 0x92, 0x93,
2061                                                                0x94, 0x95, 0x96, 0x97, 0x98, 0x91,
2062                                                                0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
2063                                                                0x98, 0x91, 0x92, 0x93, 0x94, 0x95,
2064                                                                0x96, 0x97, 0x98
2065                                                            ])
2066                                                        )
2067                                                    )
2068                                                )
2069                                                .build()
2070                                                .unwrap()
2071                                        )
2072                                        .build()
2073                                )
2074                                .unwrap()
2075                            )]
2076                            .into()
2077                        ))
2078                        .signature(Signature::EcdsaNistP256(
2079                            EcdsaP256Signature::builder()
2080                                .r_sig(EccP256CurvePoint::CompressedY0(
2081                                    b"12345678123456781234567812345678"
2082                                        .as_slice()
2083                                        .try_into()
2084                                        .unwrap()
2085                                ))
2086                                .s_sig(
2087                                    b"ABCDEFGHABCDEFGHABCDEFGHABCDEFGH"
2088                                        .as_slice()
2089                                        .try_into()
2090                                        .unwrap()
2091                                )
2092                                .build()
2093                        ))
2094                        .build()
2095                )))
2096                .build(),
2097            // Standard-provided verification sample
2098            // 03 81 00 40 03 80 0F 54 68 69 73 20 69 73 20 61
2099            // 20 42 53 4D 0D 0A 40 01 20 11 12 13 14 15 16 17
2100            // 18 81 01 01 00 03 01 80 21 22 23 24 25 26 27 28
2101            // 50 80 80 00 64 31 32 33 34 35 36 37 38 39 41 42
2102            // 43 44 51 52 53 54 55 56 57 58 59 61 62 63 00 46
2103            // 04 E0 9A 20 84 00 A9 83 01 03 80 00 7C 80 01 E4
2104            // 80 03 48 01 02 00 01 20 00 01 26 81 82 91 92 93
2105            // 94 95 96 97 98 91 92 93 94 95 96 97 98 91 92 93
2106            // 94 95 96 97 98 91 92 93 94 95 96 97 98 80 82 31
2107            // 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 31
2108            // 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 41
2109            // 42 43 44 45 46 47 48 41 42 43 44 45 46 47 48 41
2110            // 42 43 44 45 46 47 48 41 42 43 44 45 46 47 48
2111            //
2112            // asnc1 output, compiled from standard:
2113            // 0x03, 0x81, 0x00, 0x40, 0x03, 0x80, 0x0f, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
2114            // 0x20, 0x61, 0x20, 0x42, 0x53, 0x4d, 0x0d, 0x0a, 0x40, 0x01, 0x20, 0x11, 0x12, 0x13,
2115            // 0x14, 0x15, 0x16, 0x17, 0x18, 0x81, 0x01, 0x01, 0x00, 0x03, 0x01, 0x80, 0x21, 0x22,
2116            // 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x50, 0x80, 0x80, 0x00, 0x64, 0x31, 0x32, 0x33,
2117            // 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x51, 0x52, 0x53, 0x54,
2118            // 0x55, 0x56, 0x57, 0x58, 0x59, 0x61, 0x62, 0x63, 0x00, 0x46, 0x04, 0xe0, 0x9a, 0x20,
2119            // 0x84, 0x00, 0xa9, 0x83, 0x01, 0x03, 0x80, 0x00, 0x7c, 0x80, 0x01, 0xe4, 0x80, 0x03,
2120            // 0x48, 0x01, 0x02, 0x00, 0x01, 0x20, 0x00, 0x01, 0x26, 0x81, 0x82, 0x91, 0x92, 0x93,
2121            // 0x94, 0x95, 0x96, 0x97, 0x98, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x91,
2122            // 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
2123            // 0x98, 0x80, 0x82, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33,
2124            // 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31,
2125            // 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
2126            // 0x48, 0x41, 0x42, 0x43, 0x44,0x45, 0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45,
2127            // 0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48
2128            //
2129            // NOTE below output is modified to be encoded as the extension version is being used (ToBeSignedCertificate extensions not optional)
2130            // &[
2131            //     0x03, 0x81, 0x00, 0x40, 0x03, 0x80, 0x0F, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
2132            //     0x20, 0x61, 0x20, 0x42, 0x53, 0x4D, 0x0D, 0x0A, 0x40, 0x01, 0x20, 0x11, 0x12, 0x13,
2133            //     0x14, 0x15, 0x16, 0x17, 0x18, 0x81, 0x01, 0x01, 0x00, 0x03, 0x01, 0x80, 0x21, 0x22,
2134            //     0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x50, - no extension present version
2135            //     0xd0, // preamble ends
2136            //     0x80, 0x80, 0x00, 0x64, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41,
2137            //     0x42, 0x43, 0x44, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x61, 0x62,
2138            //     0x63, 0x00, 0x46, 0x04, 0xE0, 0x9A, 0x20, 0x84, 0x00, 0xA9, 0x83, 0x01, 0x03, 0x80,
2139            //     0x00, 0x7C, 0x80, 0x01, 0xE4, 0x80, 0x03, 0x48, 0x01, 0x02, 0x00, 0x01, 0x20, 0x00,
2140            //     0x01, 0x26, 0x81, 0x82, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x91, 0x92,
2141            //     0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
2142            //     0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
2143            //     0x98, // extension bitmap starts for TBS cert
2144            //     0x02, 0x04, 0x70, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01,
2145            //     0x00, // ends
2146            //     0x80, 0x82, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34,
2147            //     0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32,
2148            //     0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
2149            //     0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
2150            //     0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48
2151            // ]
2152            &[
2153                0x03, 0x81, 0x00, 0x40, 0x03, 0x80, 0x0F, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
2154                0x20, 0x61, 0x20, 0x42, 0x53, 0x4D, 0x0D, 0x0A, 0x40, 0x01, 0x20, 0x11, 0x12, 0x13,
2155                0x14, 0x15, 0x16, 0x17, 0x18, 0x81, 0x01, 0x01, 0x00, 0x03, 0x01, 0x80, 0x21, 0x22,
2156                0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x50, 0x80, 0x80, 0x00, 0x64, 0x31, 0x32, 0x33,
2157                0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x51, 0x52, 0x53, 0x54,
2158                0x55, 0x56, 0x57, 0x58, 0x59, 0x61, 0x62, 0x63, 0x00, 0x46, 0x04, 0xE0, 0x9A, 0x20,
2159                0x84, 0x00, 0xA9, 0x83, 0x01, 0x03, 0x80, 0x00, 0x7C, 0x80, 0x01, 0xE4, 0x80, 0x03,
2160                0x48, 0x01, 0x02, 0x00, 0x01, 0x20, 0x00, 0x01, 0x26, 0x81, 0x82, 0x91, 0x92, 0x93,
2161                0x94, 0x95, 0x96, 0x97, 0x98, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x91,
2162                0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
2163                0x98, 0x80, 0x82, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33,
2164                0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31,
2165                0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
2166                0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45,
2167                0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48
2168            ]
2169        );
2170    }
2171    #[test]
2172    fn sample_choice() {
2173        pub type Uint16 = u16;
2174        #[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, Eq)]
2175        #[rasn(choice, automatic_tags)]
2176        pub enum Duration {
2177            Microseconds(Uint16),
2178            Milliseconds(Uint16),
2179            Seconds(Uint16),
2180            Minutes(Uint16),
2181            Hours(Uint16),
2182            SixtyHours(Uint16),
2183            Years(Uint16),
2184        }
2185        let duration = Duration::Hours(10);
2186        let output = rasn::coer::encode(&duration).unwrap();
2187        assert_eq!(
2188            rasn::coer::decode::<Duration>(output.as_slice()).unwrap(),
2189            duration
2190        );
2191    }
2192}