• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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