x509_signature/
lib.rs

1//! # A low-level X.509 parsing and certificate signature verification library.
2//!
3//! x509-signature can verify the signatures of X.509 certificates, as well as
4//! certificates made by their private keys.  It can also verify that a
5//! certificate is valid for the given time. However, it is (by design) very
6//! low-level: it does not know about *any* X.509 extensions, and does not parse
7//! distinguished names at all.  It also provides no path-building facilities.
8//! As such, it is not intended for use with the web PKI; use webpki for that.
9//!
10//! x509-signature’s flexibiity is a double-edged sword: it allows it to be used
11//! in situations where webpki cannot be used, but it also makes it
12//! significantly more dangerous.  As a general rule, x509-signature will accept
13//! any certificate that webpki will, but it will also accept certificates that
14//! webpki will reject.  If you find a certificate that x509-signature rejects
15//! and webpki rejects, please report it as a bug.
16//!
17//! x509-signature was developed for use with
18//! [libp2p](https://github.com/libp2p), which uses certificates that webpki
19//! cannot handle.  Its bare-bones design ensures that it can handle almost any
20//! conforming X.509 certificate, but it also means that the application is
21//! responsible for ensuring that the certificate has valid X.509 extensions.
22//! x509-signature cannot distinguish between a certificate valid for
23//! `mozilla.org` and one for `evilmalware.com`!  However, x509-signature
24//! does provide the hooks needed for higher-level libraries to be built on top
25//! of it.
26//!
27//! Like webpki, x509-signature is zero-copy and `#![no_std]` friendly.  If
28//! built without the `alloc` feature, x509-signature will not rely on features
29//! of *ring* that require heap allocation, specifically RSA.  x509-signature
30//! should never panic on any input.
31
32#![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/// A signature scheme supported by this library
77#[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 PKCS#1 signatures with SHA256
83    RSA_PKCS1_SHA256,
84    /// RSA PKCS#1 signatures with SHA384
85    RSA_PKCS1_SHA384,
86    /// RSA PKCS#1 signatures with SHA512
87    RSA_PKCS1_SHA512,
88    /// ECDSA signatures with SHA256
89    ECDSA_NISTP256_SHA256,
90    /// ECDSA signatures with SHA384
91    ECDSA_NISTP384_SHA384,
92    /// ed25519 signatures
93    ED25519,
94    /// RSA-PSS signatures with SHA256
95    RSA_PSS_SHA256,
96    /// RSA-PSS signatures with SHA384
97    RSA_PSS_SHA384,
98    /// RSA-PSS signatures with SHA512
99    RSA_PSS_SHA512,
100    /// ed448 signatures
101    ED448,
102}
103
104#[cfg(not(feature = "webpki"))]
105/// Errors that can be produced when parsing a certificate or validating a
106/// signature.
107///
108/// More errors may be added in the future.
109#[non_exhaustive]
110#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
111pub enum Error {
112    /// Version is not 3
113    UnsupportedCertVersion,
114    /// Signature algorithm unsupported
115    UnsupportedSignatureAlgorithm,
116    /// Signature algorithm isn’t valid for the public key
117    UnsupportedSignatureAlgorithmForPublicKey,
118    /// Signature forged!
119    InvalidSignatureForPublicKey,
120    /// Signature algorithms don’t match
121    SignatureAlgorithmMismatch,
122    /// Invalid DER
123    BadDER,
124    /// Invalid DER time
125    BadDERTime,
126    /// Certificate isn’t valid yet
127    CertNotValidYet,
128    /// Certificate has expired
129    CertExpired,
130    /// Certificate expired before beginning to be valid
131    InvalidCertValidity,
132    /// The issuer is not known.
133    UnknownIssuer,
134}
135
136#[cfg(feature = "webpki")]
137pub use w::Error;
138
139/// A parsed (but not validated) X.509 version 3 certificate.
140#[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    /// The tbsCertificate, signatureAlgorithm, and signature
154    pub fn das(&self) -> DataAlgorithmSignature<'a> { self.das }
155
156    /// The serial number. Big-endian and non-empty. The first byte is
157    /// guaranteed to be non-zero.
158    pub fn serial(&self) -> &'a [u8] { self.serial }
159
160    /// The X.509 issuer. This has not been validated and is not trusted. In
161    /// particular, it is not guaranteed to be valid ASN.1 DER.
162    pub fn issuer(&self) -> &'a [u8] { self.issuer }
163
164    /// The earliest time, in seconds since the Unix epoch, that the certificate
165    /// is valid.
166    ///
167    /// Will always be between [`MIN_ASN1_TIMESTAMP`] and
168    /// [`MAX_ASN1_TIMESTAMP`], inclusive.
169    pub fn not_before(&self) -> ASN1Time { self.not_before }
170
171    /// The latest time, in seconds since the Unix epoch, that the certificate
172    /// is valid.
173    ///
174    /// Will always be between [`MIN_ASN1_TIMESTAMP`] and
175    /// [`MAX_ASN1_TIMESTAMP`], inclusive.
176    pub fn not_after(&self) -> ASN1Time { self.not_after }
177
178    /// X.509 subject. This has not been validated and is not trusted. In
179    /// particular, it is not guaranteed to be valid ASN.1 DER.
180    pub fn subject(&self) -> &'a [u8] { self.subject }
181
182    /// The subjectPublicKeyInfo, encoded as ASN.1 DER. There is no guarantee
183    /// that the OID or public key are valid ASN.1 DER, but if they are not,
184    /// all methods that check signatures will fail.
185    pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfo<'a> {
186        self.subject_public_key_info
187    }
188
189    /// An iterator over the certificate’s extensions.
190    pub fn extensions(&self) -> ExtensionIterator<'a> { self.extensions }
191
192    /// Verify a signature made by the certificate.
193    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    /// Verify a signature made by the certificate, applying the restrictions of
205    /// TLSv1.3:
206    ///
207    /// * ECDSA algorithms where the hash has a different size than the curve
208    ///   are not allowed.
209    /// * RSA PKCS1.5 signatures are not allowed.
210    ///
211    /// This is a good choice for new protocols and applications. Note that
212    /// extensions are not checked, so applications must process extensions
213    /// themselves.
214    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    /// Verify a signature made by the certificate, applying the restrictions of
226    /// TLSv1.2:
227    ///
228    /// * RSA-PSS signatures are not allowed.
229    ///
230    /// This should not be used outside of a TLSv1.2 implementation. Note that
231    /// extensions are not checked, so applications must process extensions
232    /// themselves.
233    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    /// Check that the certificate is valid at time `now`, in seconds since the
245    /// Epoch.
246    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    /// Check if a certificate is currently valid.
257    #[cfg(feature = "std")]
258    pub fn valid(&self) -> Result<(), Error> { self.valid_at_timestamp(ASN1Time::now()?.into()) }
259
260    /// The tbsCertficate
261    pub fn tbs_certificate(&self) -> &[u8] { self.das.data() }
262
263    /// The `AlgorithmId` of the algorithm used to sign this certificate
264    pub fn signature_algorithm_id(&self) -> &[u8] { self.das.algorithm() }
265
266    /// The signature of the certificate
267    pub fn signature(&self) -> &[u8] { self.das.signature() }
268
269    /// Verify that this certificate was signed by `cert`’s secret key.
270    ///
271    /// This does not check that `cert` is a certificate authority.
272    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    /// As above, but also check that `self`’s issuer is `cert`’s subject.
281    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    /// Check that this certificate is self-signed. This does not check that the
289    /// subject and issuer are equal.
290    #[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    /// Check that this certificate is self-signed, and that the subject and
294    /// issuer are equal.
295    pub fn check_self_issued(&self) -> Result<(), Error> { self.check_issued_by(self) }
296}
297
298/// Extracts the algorithm id and public key from a certificate
299pub 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        // We require extensions, which means we require version 3
304        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        // serialNumber
310        let serial = der::positive_integer(input)
311            .map_err(|_| Error::BadDER)?
312            .big_endian_without_leading_zero();
313        // signature
314        if das::read_sequence(input)?.as_slice_less_safe() != das.algorithm() {
315            // signature algorithms don’t match
316            return Err(Error::SignatureAlgorithmMismatch);
317        }
318        // issuer
319        let issuer = das::read_sequence(input)?.as_slice_less_safe();
320        // validity
321        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        // subjectUniqueId and issuerUniqueId are unsupported
331
332        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}