webpki/cert.rs
1// Copyright 2015 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use crate::der::Tag;
16use crate::signed_data::SignedData;
17use crate::x509::{remember_extension, set_extension_once, Extension};
18use crate::{der, public_values_eq, Error};
19
20/// An enumeration indicating whether a [`Cert`] is a leaf end-entity cert, or a linked
21/// list node from the CA `Cert` to a child `Cert` it issued.
22pub enum EndEntityOrCa<'a> {
23 /// The [`Cert`] is a leaf end-entity certificate.
24 EndEntity,
25
26 /// The [`Cert`] is an issuer certificate, and issued the referenced child `Cert`.
27 Ca(&'a Cert<'a>),
28}
29
30/// A parsed X509 certificate.
31pub struct Cert<'a> {
32 pub(crate) ee_or_ca: EndEntityOrCa<'a>,
33
34 pub(crate) serial: untrusted::Input<'a>,
35 pub(crate) signed_data: SignedData<'a>,
36 pub(crate) issuer: untrusted::Input<'a>,
37 pub(crate) validity: untrusted::Input<'a>,
38 pub(crate) subject: untrusted::Input<'a>,
39 pub(crate) spki: der::Value<'a>,
40
41 pub(crate) basic_constraints: Option<untrusted::Input<'a>>,
42 // key usage (KU) extension (if any). When validating certificate revocation lists (CRLs) this
43 // field will be consulted to determine if the cert is allowed to sign CRLs. For cert validation
44 // this field is ignored (for more detail see in `verify_cert.rs` and
45 // `check_issuer_independent_properties`).
46 pub(crate) key_usage: Option<untrusted::Input<'a>>,
47 pub(crate) eku: Option<untrusted::Input<'a>>,
48 pub(crate) name_constraints: Option<untrusted::Input<'a>>,
49 pub(crate) subject_alt_name: Option<untrusted::Input<'a>>,
50}
51
52impl<'a> Cert<'a> {
53 pub(crate) fn from_der(
54 cert_der: untrusted::Input<'a>,
55 ee_or_ca: EndEntityOrCa<'a>,
56 ) -> Result<Self, Error> {
57 let (tbs, signed_data) = cert_der.read_all(Error::BadDer, |cert_der| {
58 der::nested(cert_der, der::Tag::Sequence, Error::BadDer, |der| {
59 // limited to SEQUENCEs of size 2^16 or less.
60 SignedData::from_der(der, der::TWO_BYTE_DER_SIZE)
61 })
62 })?;
63
64 tbs.read_all(Error::BadDer, |tbs| {
65 version3(tbs)?;
66
67 let serial = lenient_certificate_serial_number(tbs)?;
68
69 let signature = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
70 // TODO: In mozilla::pkix, the comparison is done based on the
71 // normalized value (ignoring whether or not there is an optional NULL
72 // parameter for RSA-based algorithms), so this may be too strict.
73 if !public_values_eq(signature, signed_data.algorithm) {
74 return Err(Error::SignatureAlgorithmMismatch);
75 }
76
77 let issuer = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
78 let validity = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
79 let subject = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
80 let spki = der::expect_tag(tbs, der::Tag::Sequence)?;
81
82 // In theory there could be fields [1] issuerUniqueID and [2]
83 // subjectUniqueID, but in practice there never are, and to keep the
84 // code small and simple we don't accept any certificates that do
85 // contain them.
86
87 let mut cert = Cert {
88 ee_or_ca,
89
90 signed_data,
91 serial,
92 issuer,
93 validity,
94 subject,
95 spki,
96
97 basic_constraints: None,
98 key_usage: None,
99 eku: None,
100 name_constraints: None,
101 subject_alt_name: None,
102 };
103
104 if !tbs.at_end() {
105 der::nested(
106 tbs,
107 der::Tag::ContextSpecificConstructed3,
108 Error::MalformedExtensions,
109 |tagged| {
110 der::nested_of_mut(
111 tagged,
112 der::Tag::Sequence,
113 der::Tag::Sequence,
114 Error::BadDer,
115 |extension| {
116 remember_cert_extension(&mut cert, &Extension::parse(extension)?)
117 },
118 )
119 },
120 )?;
121 }
122
123 Ok(cert)
124 })
125 }
126
127 /// Raw DER encoded certificate serial number.
128 pub fn serial(&self) -> &[u8] {
129 self.serial.as_slice_less_safe()
130 }
131
132 /// Raw DER encoded certificate issuer.
133 pub fn issuer(&self) -> &[u8] {
134 self.issuer.as_slice_less_safe()
135 }
136
137 /// Raw DER encoded certificate subject.
138 pub fn subject(&self) -> &[u8] {
139 self.subject.as_slice_less_safe()
140 }
141
142 /// Returns an indication of whether the certificate is an end-entity (leaf) certificate,
143 /// or a certificate authority.
144 pub fn end_entity_or_ca(&self) -> &EndEntityOrCa {
145 &self.ee_or_ca
146 }
147}
148
149// mozilla::pkix supports v1, v2, v3, and v4, including both the implicit
150// (correct) and explicit (incorrect) encoding of v1. We allow only v3.
151fn version3(input: &mut untrusted::Reader) -> Result<(), Error> {
152 der::nested(
153 input,
154 der::Tag::ContextSpecificConstructed0,
155 Error::UnsupportedCertVersion,
156 |input| {
157 let version = der::small_nonnegative_integer(input)?;
158 if version != 2 {
159 // v3
160 return Err(Error::UnsupportedCertVersion);
161 }
162 Ok(())
163 },
164 )
165}
166
167pub(crate) fn lenient_certificate_serial_number<'a>(
168 input: &mut untrusted::Reader<'a>,
169) -> Result<untrusted::Input<'a>, Error> {
170 // https://tools.ietf.org/html/rfc5280#section-4.1.2.2:
171 // * Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
172 // * "The serial number MUST be a positive integer [...]"
173 //
174 // However, we don't enforce these constraints, as there are widely-deployed trust anchors
175 // and many X.509 implementations in common use that violate these constraints. This is called
176 // out by the same section of RFC 5280 as cited above:
177 // Note: Non-conforming CAs may issue certificates with serial numbers
178 // that are negative or zero. Certificate users SHOULD be prepared to
179 // gracefully handle such certificates.
180 der::expect_tag_and_get_value(input, Tag::Integer)
181}
182
183fn remember_cert_extension<'a>(
184 cert: &mut Cert<'a>,
185 extension: &Extension<'a>,
186) -> Result<(), Error> {
187 // We don't do anything with certificate policies so we can safely ignore
188 // all policy-related stuff. We assume that the policy-related extensions
189 // are not marked critical.
190
191 remember_extension(extension, |id| {
192 let out = match id {
193 // id-ce-keyUsage 2.5.29.15.
194 15 => &mut cert.key_usage,
195
196 // id-ce-subjectAltName 2.5.29.17
197 17 => &mut cert.subject_alt_name,
198
199 // id-ce-basicConstraints 2.5.29.19
200 19 => &mut cert.basic_constraints,
201
202 // id-ce-nameConstraints 2.5.29.30
203 30 => &mut cert.name_constraints,
204
205 // id-ce-extKeyUsage 2.5.29.37
206 37 => &mut cert.eku,
207
208 // Unsupported extension
209 _ => return extension.unsupported(),
210 };
211
212 set_extension_once(out, || {
213 extension.value.read_all(Error::BadDer, |value| match id {
214 // Unlike the other extensions we remember KU is a BitString and not a Sequence. We
215 // read the raw bytes here and parse at the time of use.
216 15 => Ok(value.read_bytes_to_end()),
217 // All other remembered certificate extensions are wrapped in a Sequence.
218 _ => der::expect_tag_and_get_value(value, Tag::Sequence),
219 })
220 })
221 })
222}
223
224#[cfg(test)]
225mod tests {
226 use crate::cert::{Cert, EndEntityOrCa};
227
228 #[test]
229 // Note: cert::parse_cert is crate-local visibility, and EndEntityCert doesn't expose the
230 // inner Cert, or the serial number. As a result we test that the raw serial value
231 // is read correctly here instead of in tests/integration.rs.
232 fn test_serial_read() {
233 let ee = include_bytes!("../tests/misc/serial_neg_ee.der");
234 let cert = Cert::from_der(untrusted::Input::from(ee), EndEntityOrCa::EndEntity)
235 .expect("failed to parse certificate");
236 assert_eq!(cert.serial.as_slice_less_safe(), &[255, 33, 82, 65, 17]);
237
238 let ee = include_bytes!("../tests/misc/serial_large_positive.der");
239 let cert = Cert::from_der(untrusted::Input::from(ee), EndEntityOrCa::EndEntity)
240 .expect("failed to parse certificate");
241 assert_eq!(
242 cert.serial.as_slice_less_safe(),
243 &[
244 0, 230, 9, 254, 122, 234, 0, 104, 140, 224, 36, 180, 237, 32, 27, 31, 239, 82, 180,
245 68, 209
246 ]
247 )
248 }
249}