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