x509_cert/
request.rs

1//! PKCS#10 Certification Request types
2
3use crate::{
4    attr::{Attribute, AttributeValue, Attributes},
5    ext::Extension,
6    name::Name,
7};
8
9use alloc::vec::Vec;
10
11use const_oid::db::rfc5912::ID_EXTENSION_REQ;
12use const_oid::{AssociatedOid, ObjectIdentifier};
13use der::asn1::BitString;
14use der::{
15    asn1::{Any, SetOfVec},
16    Decode, Enumerated, Sequence,
17};
18use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned};
19
20#[cfg(feature = "pem")]
21use der::pem::PemLabel;
22
23/// Version identifier for certification request information.
24///
25/// (RFC 2986 designates `0` as the only valid version)
26#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated, Default)]
27#[asn1(type = "INTEGER")]
28#[repr(u8)]
29pub enum Version {
30    /// Denotes PKCS#8 v1
31    #[default]
32    V1 = 0,
33}
34
35/// PKCS#10 `CertificationRequestInfo` as defined in [RFC 2986 Section 4].
36///
37/// ```text
38/// CertificationRequestInfo ::= SEQUENCE {
39///     version       INTEGER { v1(0) } (v1,...),
40///     subject       Name,
41///     subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
42///     attributes    [0] Attributes{{ CRIAttributes }}
43/// }
44/// ```
45///
46/// [RFC 2986 Section 4]: https://datatracker.ietf.org/doc/html/rfc2986#section-4
47#[derive(Clone, Debug, PartialEq, Eq, Sequence)]
48pub struct CertReqInfo {
49    /// Certification request version.
50    pub version: Version,
51
52    /// Subject name.
53    pub subject: Name,
54
55    /// Subject public key info.
56    pub public_key: SubjectPublicKeyInfoOwned,
57
58    /// Request attributes.
59    #[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
60    pub attributes: Attributes,
61}
62
63/// PKCS#10 `CertificationRequest` as defined in [RFC 2986 Section 4].
64///
65/// ```text
66/// CertificationRequest ::= SEQUENCE {
67///     certificationRequestInfo CertificationRequestInfo,
68///     signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
69///     signature          BIT STRING
70/// }
71/// ```
72///
73/// [RFC 2986 Section 4]: https://datatracker.ietf.org/doc/html/rfc2986#section-4
74#[derive(Clone, Debug, PartialEq, Eq, Sequence)]
75pub struct CertReq {
76    /// Certification request information.
77    pub info: CertReqInfo,
78
79    /// Signature algorithm identifier.
80    pub algorithm: AlgorithmIdentifierOwned,
81
82    /// Signature.
83    pub signature: BitString,
84}
85
86#[cfg(feature = "pem")]
87impl PemLabel for CertReq {
88    const PEM_LABEL: &'static str = "CERTIFICATE REQUEST";
89}
90
91impl<'a> TryFrom<&'a [u8]> for CertReq {
92    type Error = der::Error;
93
94    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
95        Self::from_der(bytes)
96    }
97}
98
99/// `ExtensionReq` as defined in [RFC 5272 Section 3.1].
100///
101/// ```text
102/// ExtensionReq ::= SEQUENCE SIZE (1..MAX) OF Extension
103/// ```
104///
105/// [RFC 5272 Section 3.1]: https://datatracker.ietf.org/doc/html/rfc5272#section-3.1
106#[derive(Clone, Debug, PartialEq, Eq, Default)]
107pub struct ExtensionReq(pub Vec<Extension>);
108
109impl AssociatedOid for ExtensionReq {
110    const OID: ObjectIdentifier = ID_EXTENSION_REQ;
111}
112
113impl_newtype!(ExtensionReq, Vec<Extension>);
114
115impl TryFrom<ExtensionReq> for Attribute {
116    type Error = der::Error;
117
118    fn try_from(extension_req: ExtensionReq) -> der::Result<Attribute> {
119        let mut values: SetOfVec<AttributeValue> = Default::default();
120        values.insert(Any::encode_from(&extension_req.0)?)?;
121
122        Ok(Attribute {
123            oid: ExtensionReq::OID,
124            values,
125        })
126    }
127}
128
129pub mod attributes {
130    //! Set of attributes that may be associated to a request
131
132    use alloc::vec;
133    use const_oid::AssociatedOid;
134    use der::{
135        asn1::{Any, ObjectIdentifier, SetOfVec},
136        EncodeValue, Length, Result, Tag, Tagged, Writer,
137    };
138
139    use crate::{attr::Attribute, ext::pkix::name::DirectoryString};
140
141    /// Trait to be implement by request attributes
142    pub trait AsAttribute: AssociatedOid + Tagged + EncodeValue + Sized {
143        /// Returns the Attribute with the content encoded.
144        fn to_attribute(&self) -> Result<Attribute> {
145            let inner: Any = der::asn1::Any::encode_from(self)?;
146
147            let values = SetOfVec::try_from(vec![inner])?;
148
149            Ok(Attribute {
150                oid: Self::OID,
151                values,
152            })
153        }
154    }
155
156    /// `ChallengePassword` as defined in [RFC 2985 Section 5.4.1]
157    ///
158    /// ```text
159    /// challengePassword ATTRIBUTE ::= {
160    ///          WITH SYNTAX DirectoryString {pkcs-9-ub-challengePassword}
161    ///          EQUALITY MATCHING RULE caseExactMatch
162    ///          SINGLE VALUE TRUE
163    ///          ID pkcs-9-at-challengePassword
164    ///  }
165    /// ```
166    ///
167    /// [RFC 2985 Section 5.4.1]: https://www.rfc-editor.org/rfc/rfc2985#page-16
168    pub struct ChallengePassword(pub DirectoryString);
169
170    impl AsAttribute for ChallengePassword {}
171
172    impl AssociatedOid for ChallengePassword {
173        const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.7");
174    }
175
176    impl Tagged for ChallengePassword {
177        fn tag(&self) -> Tag {
178            self.0.tag()
179        }
180    }
181
182    impl EncodeValue for ChallengePassword {
183        fn value_len(&self) -> Result<Length> {
184            self.0.value_len()
185        }
186
187        fn encode_value(&self, encoder: &mut impl Writer) -> Result<()> {
188            self.0.encode_value(encoder)
189        }
190    }
191}