Skip to main content

x509_parser/
certification_request.rs

1use crate::cri_attributes::*;
2use crate::error::{X509Error, X509Result};
3use crate::extensions::*;
4use crate::x509::{
5    parse_signature_value, AlgorithmIdentifier, SubjectPublicKeyInfo, X509Name, X509Version,
6};
7
8#[cfg(any(feature = "verify", feature = "verify-aws"))]
9use crate::verify::verify_signature;
10use asn1_rs::{BitString, FromDer};
11use der_parser::der::*;
12use der_parser::*;
13use nom::Offset;
14use std::collections::HashMap;
15
16/// Certification Signing Request (CSR)
17#[derive(Debug, PartialEq)]
18pub struct X509CertificationRequest<'a> {
19    pub certification_request_info: X509CertificationRequestInfo<'a>,
20    pub signature_algorithm: AlgorithmIdentifier<'a>,
21    pub signature_value: BitString<'a>,
22
23    /// Complete raw ASN.1 DER content (request info, signature algorithm and signature).
24    pub(crate) raw: &'a [u8],
25}
26
27impl<'a> X509CertificationRequest<'a> {
28    /// Return the raw ASN.1 DER content of the complete signed certification request that was parsed.
29    ///
30    /// This includes the certification request info, the signature algorithm, and the signature.
31    ///
32    /// We avoid the `AsRef` trait in this instance to ensure the full lifetime of the `X509CertificationRequest` is used.
33    pub fn as_raw(&self) -> &'a [u8] {
34        self.raw
35    }
36
37    pub fn requested_extensions(&self) -> Option<impl Iterator<Item = &ParsedExtension<'_>>> {
38        self.certification_request_info
39            .iter_attributes()
40            .find_map(|attr| {
41                if let ParsedCriAttribute::ExtensionRequest(requested) = &attr.parsed_attribute {
42                    Some(requested.extensions.iter().map(|ext| &ext.parsed_extension))
43                } else {
44                    None
45                }
46            })
47    }
48
49    /// Verify the cryptographic signature of this certification request
50    ///
51    /// Uses the public key contained in the CSR, which must be the one of the entity
52    /// requesting the certification for this verification to succeed.
53    #[cfg(any(feature = "verify", feature = "verify-aws"))]
54    #[cfg_attr(docsrs, doc(cfg(any(feature = "verify", feature = "verify-aws"))))]
55    pub fn verify_signature(&self) -> Result<(), X509Error> {
56        let spki = &self.certification_request_info.subject_pki;
57        verify_signature(
58            spki,
59            &self.signature_algorithm,
60            &self.signature_value,
61            self.certification_request_info.raw,
62        )
63    }
64}
65
66impl<'a> AsRef<[u8]> for X509CertificationRequest<'a> {
67    fn as_ref(&self) -> &[u8] {
68        self.as_raw()
69    }
70}
71
72/// <pre>
73/// CertificationRequest ::= SEQUENCE {
74///     certificationRequestInfo CertificationRequestInfo,
75///     signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
76///     signature          BIT STRING
77/// }
78/// </pre>
79impl<'a> FromDer<'a, X509Error> for X509CertificationRequest<'a> {
80    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
81        let start_i = i;
82        let (rem, mut req) = parse_der_sequence_defined_g(|i, _| {
83            let (i, certification_request_info) = X509CertificationRequestInfo::from_der(i)?;
84            let (i, signature_algorithm) = AlgorithmIdentifier::from_der(i)?;
85            let (i, signature_value) = parse_signature_value(i)?;
86            let cert = X509CertificationRequest {
87                certification_request_info,
88                signature_algorithm,
89                signature_value,
90                raw: &[],
91            };
92            Ok((i, cert))
93        })(i)?;
94        let len = start_i.offset(rem);
95        req.raw = &start_i[..len];
96        Ok((rem, req))
97    }
98}
99
100/// Certification Request Info structure
101///
102/// Certification request information is defined by the following ASN.1 structure:
103///
104/// <pre>
105/// CertificationRequestInfo ::= SEQUENCE {
106///      version       INTEGER { v1(0) } (v1,...),
107///      subject       Name,
108///      subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
109///      attributes    [0] Attributes{{ CRIAttributes }}
110/// }
111/// </pre>
112///
113/// version is the version number; subject is the distinguished name of the certificate
114/// subject; subject_pki contains information about the public key being certified, and
115/// attributes is a collection of attributes providing additional information about the
116/// subject of the certificate.
117#[derive(Debug, PartialEq)]
118pub struct X509CertificationRequestInfo<'a> {
119    pub version: X509Version,
120    pub subject: X509Name<'a>,
121    pub subject_pki: SubjectPublicKeyInfo<'a>,
122    attributes: Vec<X509CriAttribute<'a>>,
123    pub raw: &'a [u8],
124}
125
126impl X509CertificationRequestInfo<'_> {
127    /// Get the CRL entry extensions.
128    #[inline]
129    pub fn attributes(&self) -> &[X509CriAttribute<'_>] {
130        &self.attributes
131    }
132
133    /// Returns an iterator over the CRL entry extensions
134    #[inline]
135    pub fn iter_attributes(&self) -> impl Iterator<Item = &X509CriAttribute<'_>> {
136        self.attributes.iter()
137    }
138
139    /// Searches for a CRL entry extension with the given `Oid`.
140    ///
141    /// Note: if there are several extensions with the same `Oid`, the first one is returned.
142    pub fn find_attribute(&self, oid: &Oid) -> Option<&X509CriAttribute<'_>> {
143        self.attributes.iter().find(|&ext| ext.oid == *oid)
144    }
145
146    /// Builds and returns a map of CRL entry extensions.
147    ///
148    /// If an extension is present twice, this will fail and return `DuplicateExtensions`.
149    pub fn attributes_map(&self) -> Result<HashMap<Oid<'_>, &X509CriAttribute<'_>>, X509Error> {
150        self.attributes
151            .iter()
152            .try_fold(HashMap::new(), |mut m, ext| {
153                if m.contains_key(&ext.oid) {
154                    return Err(X509Error::DuplicateAttributes);
155                }
156                m.insert(ext.oid.clone(), ext);
157                Ok(m)
158            })
159    }
160}
161
162/// <pre>
163/// CertificationRequestInfo ::= SEQUENCE {
164///      version       INTEGER { v1(0) } (v1,...),
165///      subject       Name,
166///      subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
167///      attributes    [0] Attributes{{ CRIAttributes }}
168/// }
169/// </pre>
170impl<'a> FromDer<'a, X509Error> for X509CertificationRequestInfo<'a> {
171    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
172        let start_i = i;
173        parse_der_sequence_defined_g(move |i, _| {
174            let (i, version) = X509Version::from_der(i)?;
175            let (i, subject) = X509Name::from_der(i)?;
176            let (i, subject_pki) = SubjectPublicKeyInfo::from_der(i)?;
177            let (i, attributes) = parse_cri_attributes(i)?;
178            let len = start_i.offset(i);
179            let tbs = X509CertificationRequestInfo {
180                version,
181                subject,
182                subject_pki,
183                attributes,
184                raw: &start_i[..len],
185            };
186            Ok((i, tbs))
187        })(i)
188    }
189}