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