Skip to content

rusticata/x509-parser

Repository files navigation

License: MIT Apache License 2.0 docs.rs crates.io Download numbers Github CI Minimum rustc version

X.509 Parser

A X.509 v3 (RFC5280) parser, implemented with the nom parser combinator framework.

It is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken to ensure security and safety of this crate, including design (recursion limit, defensive programming), tests, and fuzzing. It also aims to be panic-free.

The code is available on Github and is part of the Rusticata project.

Certificates are usually encoded in two main formats: PEM (usually the most common format) or DER. A PEM-encoded certificate is a container, storing a DER object. See the pem module for more documentation.

To decode a DER-encoded certificate, the main parsing method is X509Certificate::parse_der (from the DerParser trait) which builds a X509Certificate object.

The parse_der trait takes an Input object, which can be built from the input bytes. This helps tracking offsets (in case of error). For convenience, the [X509Certificate::from_der] method (part of the FromDer trait) does the same directly on the input bytes, but it can loose the precise error location.

An alternative method is to use X509CertificateParser, which allows specifying parsing options (for example, not automatically parsing option contents).

Similar methods are provided for other X.509 objects:

The returned objects for parsers follow the definitions of the RFC. This means that accessing fields is done by accessing struct members recursively. Some helper functions are provided, for example X509Certificate::issuer() returns the same as accessing <object>.tbs_certificate.issuer.

For PEM-encoded certificates, use the pem module.

This crate also provides visitor traits: X509CertificateVisitor, CertificateRevocationListVisitor. See the visitor module.

Examples

Parsing a certificate in DER format:

use x509_parser::prelude::*;

static IGCA_DER: &[u8] = include_bytes!("../assets/IGC_A.der");

let input = Input::from(IGCA_DER);
let res = X509Certificate::parse_der(input);
match res {
    Ok((rem, cert)) => {
        assert!(rem.is_empty());
        //
        assert_eq!(cert.version(), X509Version::V3);
    },
    _ => panic!("x509 parsing failed: {:?}", res),
}

To parse a CRL and print information about revoked certificates:

let input = Input::from(DER);
let res = CertificateRevocationList::parse_der(input);
match res {
    Ok((_rem, crl)) => {
        for revoked in crl.iter_revoked_certificates() {
            println!("Revoked certificate serial: {}", revoked.raw_serial_as_string());
            println!("  Reason: {}", revoked.reason_code().unwrap_or_default().1);
        }
    },
    _ => panic!("CRL parsing failed: {:?}", res),
}

See also examples/print-cert.rs.

Features

  • The verify and verify-aws features add support for (cryptographic) signature verification, based on ring or aws-lc respectively. It adds the X509Certificate::verify_signature() method to X509Certificate.
/// Cryptographic signature verification: returns true if certificate was signed by issuer
#[cfg(any(feature = "verify", feature = "verify-aws"))]
pub fn check_signature(cert: &X509Certificate<'_>, issuer: &X509Certificate<'_>) -> bool {
    let issuer_public_key = issuer.public_key();
    cert
        .verify_signature(Some(issuer_public_key))
        .is_ok()
}
  • The verify-aws feature offers the same support for signature verification, but based on aws-lc-rs instead of ring.

  • Note: if both verify and verify-aws features are enabled (which happens when using --all-features), the verification will use aws-lc-rs. It also has the side-effect of having a dependency on ring, even if it is not used.

  • The validate feature adds methods to run more validation functions on the certificate structure and values using the Validate trait. It does not validate any cryptographic parameter (see verify above).

Rust version requirements

x509-parser requires Rustc version 1.85 or greater

MSRV policy

This projects tries to maintain compatibility with older versions of the rust compiler for the following durations:

  • master branch: 12 months minimum
  • older releases: about 24 months

However, due to dependencies and the fact that some crate writers tend to require very recent versions of the compiler, this can prove to be difficult. These numbers are given as best-effort.

We do not consider MSRV changes to be breaking for the purposes of semver.

We try to make no change to MSRV in stable branches and in security patches, with the exception of a dependency that must be updated for security and requires a new MSRV.

Changes

See CHANGELOG.md and UPGRADING.md for instructions for upgrading major versions.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

X.509 parser written in pure Rust. Fast, zero-copy, safe.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages