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, signed_data, Error};
16
17pub enum EndEntityOrCA<'a> {
18 EndEntity,
19 CA(&'a Cert<'a>),
20}
21
22pub struct Cert<'a> {
23 pub ee_or_ca: EndEntityOrCA<'a>,
24
25 pub signed_data: signed_data::SignedData<'a>,
26 pub issuer: untrusted::Input<'a>,
27 pub validity: untrusted::Input<'a>,
28 pub subject: untrusted::Input<'a>,
29 pub spki: der::Value<'a>,
30
31 pub basic_constraints: Option<untrusted::Input<'a>>,
32 pub eku: Option<untrusted::Input<'a>>,
33 pub name_constraints: Option<untrusted::Input<'a>>,
34 pub subject_alt_name: Option<untrusted::Input<'a>>,
35}
36
37pub fn parse_cert<'a>(
38 cert_der: untrusted::Input<'a>, ee_or_ca: EndEntityOrCA<'a>,
39) -> Result<Cert<'a>, Error> {
40 parse_cert_internal(cert_der, ee_or_ca, certificate_serial_number)
41}
42
43/// Used by `parse_cert` for regular certificates (end-entity and intermediate)
44/// and by `cert_der_as_trust_anchor` for trust anchors encoded as
45/// certificates.
46pub(crate) fn parse_cert_internal<'a>(
47 cert_der: untrusted::Input<'a>, ee_or_ca: EndEntityOrCA<'a>,
48 serial_number: fn(input: &mut untrusted::Reader<'_>) -> Result<(), Error>,
49) -> Result<Cert<'a>, Error> {
50 let (tbs, signed_data) = cert_der.read_all(Error::BadDER, |cert_der| {
51 der::nested(
52 cert_der,
53 der::Tag::Sequence,
54 Error::BadDER,
55 signed_data::parse_signed_data,
56 )
57 })?;
58
59 tbs.read_all(Error::BadDER, |tbs| {
60 version3(tbs)?;
61 serial_number(tbs)?;
62
63 let signature = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
64 // TODO: In mozilla::pkix, the comparison is done based on the
65 // normalized value (ignoring whether or not there is an optional NULL
66 // parameter for RSA-based algorithms), so this may be too strict.
67 if signature != signed_data.algorithm {
68 return Err(Error::SignatureAlgorithmMismatch);
69 }
70
71 let issuer = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
72 let validity = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
73 let subject = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?;
74 let spki = der::expect_tag(tbs, der::Tag::Sequence)?;
75
76 // In theory there could be fields [1] issuerUniqueID and [2]
77 // subjectUniqueID, but in practice there never are, and to keep the
78 // code small and simple we don't accept any certificates that do
79 // contain them.
80
81 let mut cert = Cert {
82 ee_or_ca,
83
84 signed_data,
85 issuer,
86 validity,
87 subject,
88 spki,
89
90 basic_constraints: None,
91 eku: None,
92 name_constraints: None,
93 subject_alt_name: None,
94 };
95
96 // mozilla::pkix allows the extensions to be omitted. However, since
97 // the subjectAltName extension is mandatory, the extensions are
98 // mandatory too, and we enforce that. Also, mozilla::pkix includes
99 // special logic for handling critical Netscape Cert Type extensions.
100 // That has been intentionally omitted.
101
102 der::nested_mut(
103 tbs,
104 der::Tag::ContextSpecificConstructed3,
105 Error::BadDER,
106 |tagged| {
107 der::nested_of_mut(
108 tagged,
109 der::Tag::Sequence,
110 der::Tag::Sequence,
111 Error::BadDER,
112 |extension| {
113 let extn_id = der::expect_tag_and_get_value(extension, der::Tag::OID)?;
114 let critical = der::optional_boolean(extension)?;
115 let extn_value =
116 der::expect_tag_and_get_value(extension, der::Tag::OctetString)?;
117 match remember_extension(&mut cert, extn_id, extn_value)? {
118 Understood::No if critical => Err(Error::UnsupportedCriticalExtension),
119 _ => Ok(()),
120 }
121 },
122 )
123 },
124 )?;
125
126 Ok(cert)
127 })
128}
129
130// mozilla::pkix supports v1, v2, v3, and v4, including both the implicit
131// (correct) and explicit (incorrect) encoding of v1. We allow only v3.
132fn version3(input: &mut untrusted::Reader) -> Result<(), Error> {
133 der::nested(
134 input,
135 der::Tag::ContextSpecificConstructed0,
136 Error::BadDER,
137 |input| {
138 let version = der::small_nonnegative_integer(input)?;
139 if version != 2 {
140 // v3
141 return Err(Error::UnsupportedCertVersion);
142 }
143 Ok(())
144 },
145 )
146}
147
148pub fn certificate_serial_number(input: &mut untrusted::Reader) -> Result<(), Error> {
149 // https://tools.ietf.org/html/rfc5280#section-4.1.2.2:
150 // * Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
151 // * "The serial number MUST be a positive integer [...]"
152
153 let value = der::positive_integer(input)?;
154 if value.big_endian_without_leading_zero().len() > 20 {
155 return Err(Error::BadDER);
156 }
157 Ok(())
158}
159
160enum Understood {
161 Yes,
162 No,
163}
164
165fn remember_extension<'a>(
166 cert: &mut Cert<'a>, extn_id: untrusted::Input, value: untrusted::Input<'a>,
167) -> Result<Understood, Error> {
168 // We don't do anything with certificate policies so we can safely ignore
169 // all policy-related stuff. We assume that the policy-related extensions
170 // are not marked critical.
171
172 // id-ce 2.5.29
173 static ID_CE: [u8; 2] = oid![2, 5, 29];
174
175 if extn_id.len() != ID_CE.len() + 1 || !extn_id.as_slice_less_safe().starts_with(&ID_CE) {
176 return Ok(Understood::No);
177 }
178
179 let out = match *extn_id.as_slice_less_safe().last().unwrap() {
180 // id-ce-keyUsage 2.5.29.15. We ignore the KeyUsage extension. For CA
181 // certificates, BasicConstraints.cA makes KeyUsage redundant. Firefox
182 // and other common browsers do not check KeyUsage for end-entities,
183 // though it would be kind of nice to ensure that a KeyUsage without
184 // the keyEncipherment bit could not be used for RSA key exchange.
185 15 => {
186 return Ok(Understood::Yes);
187 },
188
189 // id-ce-subjectAltName 2.5.29.17
190 17 => &mut cert.subject_alt_name,
191
192 // id-ce-basicConstraints 2.5.29.19
193 19 => &mut cert.basic_constraints,
194
195 // id-ce-nameConstraints 2.5.29.30
196 30 => &mut cert.name_constraints,
197
198 // id-ce-extKeyUsage 2.5.29.37
199 37 => &mut cert.eku,
200
201 _ => {
202 return Ok(Understood::No);
203 },
204 };
205
206 match *out {
207 Some(..) => {
208 // The certificate contains more than one instance of this
209 // extension.
210 return Err(Error::ExtensionValueInvalid);
211 },
212 None => {
213 // All the extensions that we care about are wrapped in a SEQUENCE.
214 let sequence_value = value.read_all(Error::BadDER, |value| {
215 der::expect_tag_and_get_value(value, der::Tag::Sequence)
216 })?;
217 *out = Some(sequence_value);
218 },
219 }
220
221 Ok(Understood::Yes)
222}