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