1#![cfg_attr(not(any(test, feature = "std")), no_std)]
33#![deny(
34 const_err,
35 deprecated,
36 improper_ctypes,
37 non_shorthand_field_patterns,
38 nonstandard_style,
39 no_mangle_generic_items,
40 renamed_and_removed_lints,
41 unknown_lints,
42 type_alias_bounds,
43 missing_copy_implementations,
44 missing_debug_implementations,
45 missing_docs,
46 single_use_lifetimes,
47 trivial_casts,
48 trivial_numeric_casts,
49 rust_2018_idioms,
50 unused,
51 future_incompatible,
52 clippy::all
53)]
54#![forbid(
55 unconditional_recursion,
56 unsafe_code,
57 intra_doc_link_resolution_failure,
58 while_true,
59 elided_lifetimes_in_paths
60)]
61
62mod das;
63mod sequence;
64mod time;
65use ring::io::der;
66mod spki;
67pub use das::DataAlgorithmSignature;
68pub use sequence::{ExtensionIterator, SequenceIterator};
69pub use spki::{parse_algorithmid, Restrictions, SubjectPublicKeyInfo};
70
71pub use time::{days_from_ymd, seconds_from_hms, ASN1Time, MAX_ASN1_TIMESTAMP, MIN_ASN1_TIMESTAMP};
72
73#[cfg(feature = "rustls")]
74pub use r::SignatureScheme;
75
76#[cfg(not(feature = "rustls"))]
78#[non_exhaustive]
79#[allow(non_camel_case_types)]
80#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
81pub enum SignatureScheme {
82 RSA_PKCS1_SHA256,
84 RSA_PKCS1_SHA384,
86 RSA_PKCS1_SHA512,
88 ECDSA_NISTP256_SHA256,
90 ECDSA_NISTP384_SHA384,
92 ED25519,
94 RSA_PSS_SHA256,
96 RSA_PSS_SHA384,
98 RSA_PSS_SHA512,
100 ED448,
102}
103
104#[cfg(not(feature = "webpki"))]
105#[non_exhaustive]
110#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
111pub enum Error {
112 UnsupportedCertVersion,
114 UnsupportedSignatureAlgorithm,
116 UnsupportedSignatureAlgorithmForPublicKey,
118 InvalidSignatureForPublicKey,
120 SignatureAlgorithmMismatch,
122 BadDER,
124 BadDERTime,
126 CertNotValidYet,
128 CertExpired,
130 InvalidCertValidity,
132 UnknownIssuer,
134}
135
136#[cfg(feature = "webpki")]
137pub use w::Error;
138
139#[derive(Debug)]
141pub struct X509Certificate<'a> {
142 das: DataAlgorithmSignature<'a>,
143 serial: &'a [u8],
144 issuer: &'a [u8],
145 not_before: ASN1Time,
146 not_after: ASN1Time,
147 subject: &'a [u8],
148 subject_public_key_info: SubjectPublicKeyInfo<'a>,
149 extensions: ExtensionIterator<'a>,
150}
151
152impl<'a> X509Certificate<'a> {
153 pub fn das(&self) -> DataAlgorithmSignature<'a> { self.das }
155
156 pub fn serial(&self) -> &'a [u8] { self.serial }
159
160 pub fn issuer(&self) -> &'a [u8] { self.issuer }
163
164 pub fn not_before(&self) -> ASN1Time { self.not_before }
170
171 pub fn not_after(&self) -> ASN1Time { self.not_after }
177
178 pub fn subject(&self) -> &'a [u8] { self.subject }
181
182 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfo<'a> {
186 self.subject_public_key_info
187 }
188
189 pub fn extensions(&self) -> ExtensionIterator<'a> { self.extensions }
191
192 pub fn check_signature(
194 &self, algorithm: SignatureScheme, message: &[u8], signature: &[u8],
195 ) -> Result<(), Error> {
196 self.subject_public_key_info.check_signature(
197 algorithm,
198 message,
199 signature,
200 Restrictions::None,
201 )
202 }
203
204 pub fn check_tls13_signature(
215 &self, algorithm: SignatureScheme, message: &[u8], signature: &[u8],
216 ) -> Result<(), Error> {
217 self.subject_public_key_info.check_signature(
218 algorithm,
219 message,
220 signature,
221 Restrictions::TLSv13,
222 )
223 }
224
225 pub fn check_tls12_signature(
234 &self, algorithm: SignatureScheme, message: &[u8], signature: &[u8],
235 ) -> Result<(), Error> {
236 self.subject_public_key_info.check_signature(
237 algorithm,
238 message,
239 signature,
240 Restrictions::TLSv12,
241 )
242 }
243
244 pub fn valid_at_timestamp(&self, now: i64) -> Result<(), Error> {
247 if now < self.not_before.into() {
248 Err(Error::CertNotValidYet)
249 } else if now > self.not_after.into() {
250 Err(Error::CertExpired)
251 } else {
252 Ok(())
253 }
254 }
255
256 #[cfg(feature = "std")]
258 pub fn valid(&self) -> Result<(), Error> { self.valid_at_timestamp(ASN1Time::now()?.into()) }
259
260 pub fn tbs_certificate(&self) -> &[u8] { self.das.data() }
262
263 pub fn signature_algorithm_id(&self) -> &[u8] { self.das.algorithm() }
265
266 pub fn signature(&self) -> &[u8] { self.das.signature() }
268
269 pub fn check_signature_from(&self, cert: &X509Certificate<'_>) -> Result<(), Error> {
273 cert.check_signature(
274 parse_algorithmid(self.signature_algorithm_id())?,
275 self.tbs_certificate(),
276 self.signature(),
277 )
278 }
279
280 pub fn check_issued_by(&self, cert: &X509Certificate<'_>) -> Result<(), Error> {
282 if self.issuer != cert.subject {
283 return Err(Error::UnknownIssuer);
284 }
285 self.check_signature_from(cert)
286 }
287
288 #[deprecated(since = "0.3.3", note = "Use check_self_issued instead")]
291 pub fn check_self_signature(&self) -> Result<(), Error> { self.check_signature_from(self) }
292
293 pub fn check_self_issued(&self) -> Result<(), Error> { self.check_issued_by(self) }
296}
297
298pub fn parse_certificate<'a>(certificate: &'a [u8]) -> Result<X509Certificate<'a>, Error> {
300 use core::convert::TryFrom as _;
301 let das = DataAlgorithmSignature::try_from(certificate)?;
302 untrusted::Input::from(&*das.inner()).read_all(Error::BadDER, |input| {
303 if input.read_bytes(5).map_err(|_| Error::BadDER)?
305 != untrusted::Input::from(&[160, 3, 2, 1, 2])
306 {
307 return Err(Error::UnsupportedCertVersion);
308 }
309 let serial = der::positive_integer(input)
311 .map_err(|_| Error::BadDER)?
312 .big_endian_without_leading_zero();
313 if das::read_sequence(input)?.as_slice_less_safe() != das.algorithm() {
315 return Err(Error::SignatureAlgorithmMismatch);
317 }
318 let issuer = das::read_sequence(input)?.as_slice_less_safe();
320 let (not_before, not_after) =
322 der::nested(input, der::Tag::Sequence, Error::BadDER, |input| {
323 Ok((time::read_time(input)?, time::read_time(input)?))
324 })?;
325 if not_before > not_after {
326 return Err(Error::InvalidCertValidity);
327 }
328 let subject = das::read_sequence(input)?.as_slice_less_safe();
329 let subject_public_key_info = SubjectPublicKeyInfo::read(input)?;
330 let extensions = if !input.at_end() {
333 let tag = der::Tag::ContextSpecificConstructed3;
334 der::nested(input, tag, Error::BadDER, |input| {
335 der::nested(input, der::Tag::Sequence, Error::BadDER, |input| {
336 if input.at_end() {
337 return Err(Error::BadDER);
338 }
339 Ok(ExtensionIterator(SequenceIterator::read(input)))
340 })
341 })
342 } else {
343 Ok(ExtensionIterator(SequenceIterator::read(input)))
344 }?;
345
346 Ok(X509Certificate {
347 das,
348 serial,
349 subject,
350 not_before,
351 not_after,
352 issuer,
353 subject_public_key_info,
354 extensions,
355 })
356 })
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362 #[test]
363 fn parses_openssl_generated_cert() {
364 let signature = include_bytes!("../testing.sig");
365 let invalid_signature = include_bytes!("../testing.bad-sig");
366 let forged_message = include_bytes!("../forged-message.txt");
367 let message = include_bytes!("../gen-bad-cert.sh");
368 let certificate = include_bytes!("../testing.crt");
369 #[cfg(feature = "rsa")]
370 let ca_certificate = include_bytes!("../ca.crt");
371
372 let cert = parse_certificate(certificate).unwrap();
373 #[cfg(feature = "rsa")]
374 let ca_cert = parse_certificate(ca_certificate).unwrap();
375 assert_eq!(
376 cert.subject_public_key_info.algorithm(),
377 include_bytes!("data/alg-ecdsa-p256.der")
378 );
379 assert_eq!(cert.subject_public_key_info.key().len(), 65);
380 cert.valid_at_timestamp(1587492766).unwrap();
381 assert_eq!(cert.valid_at_timestamp(0), Err(Error::CertNotValidYet));
382 assert_eq!(
383 cert.valid_at_timestamp(i64::max_value()),
384 Err(Error::CertExpired)
385 );
386
387 cert.check_signature(SignatureScheme::ECDSA_NISTP256_SHA256, message, signature)
388 .expect("OpenSSL generates syntactically valid certificates");
389 assert_eq!(
390 cert.check_signature(
391 SignatureScheme::ECDSA_NISTP256_SHA256,
392 message,
393 invalid_signature,
394 )
395 .expect_err("corrupting a signature invalidates it"),
396 Error::InvalidSignatureForPublicKey
397 );
398 assert_eq!(
399 cert.check_signature(
400 SignatureScheme::ECDSA_NISTP256_SHA256,
401 message,
402 invalid_signature,
403 )
404 .expect_err("corrupting a message invalidates it"),
405 Error::InvalidSignatureForPublicKey
406 );
407 assert_eq!(
408 cert.check_signature(
409 SignatureScheme::ECDSA_NISTP256_SHA256,
410 forged_message,
411 signature,
412 )
413 .expect_err("forgery undetected?"),
414 Error::InvalidSignatureForPublicKey
415 );
416 #[cfg(feature = "rsa")]
417 ca_cert.check_self_issued().unwrap();
418 #[cfg(feature = "rsa")]
419 cert.check_issued_by(&ca_cert).unwrap();
420 }
421}