x509_certificate/
rfc2986.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! ASN.1 primitives from RFC 2986.
6
7use {
8    crate::{
9        rfc3280::Name,
10        rfc5280::{AlgorithmIdentifier, SubjectPublicKeyInfo},
11        rfc5652::Attribute,
12        rfc5958::Attributes,
13    },
14    bcder::{
15        decode::{Constructed, DecodeError, Source},
16        encode::{self, PrimitiveContent, Values},
17        BitString, Integer, Mode, Tag,
18    },
19    std::io::Write,
20};
21
22#[derive(Clone, Copy, Debug)]
23pub enum Version {
24    V1 = 0,
25}
26
27impl From<Version> for u8 {
28    fn from(v: Version) -> u8 {
29        match v {
30            Version::V1 => 0,
31        }
32    }
33}
34
35impl Version {
36    pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
37        match cons.take_primitive_if(Tag::INTEGER, Integer::i8_from_primitive)? {
38            0 => Ok(Self::V1),
39            _ => Err(cons.content_err("unexpected non-integer when parsing Version")),
40        }
41    }
42
43    pub fn encode(self) -> impl Values {
44        u8::from(self).encode()
45    }
46}
47
48/// Certificate request info.
49///
50/// ```asn.1
51/// CertificationRequestInfo ::= SEQUENCE {
52///   version       INTEGER { v1(0) } (v1,...),
53///   subject       Name,
54///   subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
55///   attributes    [0] Attributes{{ CRIAttributes }}
56/// }
57/// ```
58#[derive(Clone)]
59pub struct CertificationRequestInfo {
60    pub version: Version,
61    pub subject: Name,
62    pub subject_public_key_info: SubjectPublicKeyInfo,
63    pub attributes: Attributes,
64}
65
66impl CertificationRequestInfo {
67    pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
68        cons.take_sequence(|cons| Self::from_sequence(cons))
69    }
70
71    pub fn from_sequence<S: Source>(
72        cons: &mut Constructed<S>,
73    ) -> Result<Self, DecodeError<S::Error>> {
74        let version = Version::take_from(cons)?;
75        let subject = Name::take_from(cons)?;
76        let subject_public_key_info = SubjectPublicKeyInfo::take_from(cons)?;
77        let attributes = cons.take_constructed_if(Tag::CTX_0, |cons| {
78            let mut attributes = Attributes::default();
79
80            while let Some(attribute) = Attribute::take_opt_from(cons)? {
81                attributes.push(attribute);
82            }
83
84            Ok(attributes)
85        })?;
86
87        Ok(Self {
88            version,
89            subject,
90            subject_public_key_info,
91            attributes,
92        })
93    }
94
95    pub fn encode_ref(&self) -> impl Values + '_ {
96        encode::sequence((
97            self.version.encode(),
98            self.subject.encode_ref(),
99            self.subject_public_key_info.encode_ref(),
100            self.attributes.encode_ref_as(Tag::CTX_0),
101        ))
102    }
103}
104
105impl Values for CertificationRequestInfo {
106    fn encoded_len(&self, mode: Mode) -> usize {
107        self.encode_ref().encoded_len(mode)
108    }
109
110    fn write_encoded<W: Write>(&self, mode: Mode, target: &mut W) -> Result<(), std::io::Error> {
111        self.encode_ref().write_encoded(mode, target)
112    }
113}
114
115/// Certificate request.
116///
117/// ```asn.1
118/// CertificationRequest ::= SEQUENCE {
119///   certificationRequestInfo CertificationRequestInfo,
120///   signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
121///   signature          BIT STRING
122/// }
123/// ```
124#[derive(Clone)]
125pub struct CertificationRequest {
126    pub certificate_request_info: CertificationRequestInfo,
127    pub signature_algorithm: AlgorithmIdentifier,
128    pub signature: BitString,
129}
130
131impl CertificationRequest {
132    pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
133        cons.take_sequence(|cons| Self::from_sequence(cons))
134    }
135
136    pub fn from_sequence<S: Source>(
137        cons: &mut Constructed<S>,
138    ) -> Result<Self, DecodeError<S::Error>> {
139        let certificate_request_info = CertificationRequestInfo::take_from(cons)?;
140        let signature_algorithm = AlgorithmIdentifier::take_from(cons)?;
141        let signature = BitString::take_from(cons)?;
142
143        Ok(Self {
144            certificate_request_info,
145            signature_algorithm,
146            signature,
147        })
148    }
149
150    pub fn encode_ref(&self) -> impl Values + '_ {
151        encode::sequence((
152            self.certificate_request_info.encode_ref(),
153            &self.signature_algorithm,
154            self.signature.encode_ref(),
155        ))
156    }
157
158    /// Encode this data structure to DER.
159    pub fn encode_der(&self) -> Result<Vec<u8>, std::io::Error> {
160        let mut buffer = vec![];
161        self.write_encoded(Mode::Der, &mut buffer)?;
162
163        Ok(buffer)
164    }
165
166    /// Encode the data structure to PEM.
167    pub fn encode_pem(&self) -> Result<String, std::io::Error> {
168        Ok(pem::Pem::new("CERTIFICATE REQUEST", self.encode_der()?).to_string())
169    }
170}
171
172impl Values for CertificationRequest {
173    fn encoded_len(&self, mode: Mode) -> usize {
174        self.encode_ref().encoded_len(mode)
175    }
176
177    fn write_encoded<W: Write>(&self, mode: Mode, target: &mut W) -> Result<(), std::io::Error> {
178        self.encode_ref().write_encoded(mode, target)
179    }
180}
181
182#[cfg(test)]
183mod test {
184    use super::*;
185
186    #[test]
187    fn rsa_parse() {
188        let der = include_bytes!("testdata/csr-rsa2048.der");
189
190        let csr = Constructed::decode(der.as_ref(), Mode::Der, |cons| {
191            CertificationRequest::take_from(cons)
192        })
193        .unwrap();
194
195        let mut encoded = vec![];
196        csr.write_encoded(Mode::Der, &mut encoded).unwrap();
197
198        assert_eq!(&encoded, der);
199    }
200}