x509_certificate/
lib.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Interface with X.509 certificates.
6//!
7//! This crate provides an interface to X.509 certificates.
8//!
9//! Low-level ASN.1 primitives are defined in modules having the name of the
10//! RFC in which they are defined.
11//!
12//! Higher-level primitives that most end-users will want to use are defined
13//! in sub-modules but exported from the main crate.
14//!
15//! # Features
16//!
17//! * Parse X.509 certificates from BER, DER, and PEM.
18//! * Access and manipulation of low-level ASN.1 data structures defining
19//!   certificates. See [rfc5280::Certificate] for the main X.509 certificate type.
20//! * Serialize X.509 certificates to BER, DER, and PEM.
21//! * Higher-level APIs for interfacing with [rfc3280::Name] types, which
22//!   define subject and issuer fields but have a very difficult to work with
23//!   data structure.
24//! * Rust enums defining key algorithms [KeyAlgorithm], signature algorithms
25//!   [SignatureAlgorithm], and digest algorithms [DigestAlgorithm] commonly
26//!   found in X.509 certificates. These can be converted to/from OIDs as well
27//!   as to their respective ASN.1 types that express them in X.509 certificates.
28//! * Verification of cryptographic signatures in certificates. If you have a
29//!   parsed X.509 certificate and a public key (which is embedded in the
30//!   issuing certificate), we can tell you if that certificate was signed
31//!   by that key/certificate.
32//! * Generating new X.509 certificates with an easy-to-use builder type. See
33//!   [X509CertificateBuilder].
34//!
35//! # Security Disclaimer
36//!
37//! This crate has not been audited by a security professional. It may contain
38//! severe bugs. Use in some security sensitive contexts is not advised.
39//!
40//! In particular, the ASN.1 parser isn't hardened against malicious inputs.
41//! And there are some ASN.1 types in the parsing code that will result in
42//! panics.
43//!
44//! # Known Isuses
45//!
46//! This code was originally developed as part of the [cryptographic-message-syntax]
47//! crate, which was developed to support implement Apple code signing in pure Rust.
48//! After reinventing X.509 certificate handling logic in multiple crates, it was
49//! decided to create this crate as a unified interface to managing X.509 certificates.
50//! While an attempt has been made to make the APIs useful in a standalone context,
51//! some of the history of this crate's intent may leak into its design. PRs that
52//! pass GitHub Actions to improve matters are gladly accepted!
53//!
54//! Not all ASN.1 types are implemented. You may encounter panics for some
55//! less tested code paths. Patches to improve the situation are much appreciated!
56//!
57//! We are using the bcder crate for ASN.1. Use of the yasna crate would be preferred,
58//! as it seems to be more popular. However, the author initially couldn't get yasna
59//! working with RFC 5652 ASN.1. However, this was likely due to his lack of knowledge
60//! of ASN.1 at the time. A port to yasna (or any other ASN.1 parser) might be in the
61//! future.
62//!
63//! Because of the history of this crate, many tests covering its functionality exist
64//! elsewhere in the repo. Overall test coverage could also likely be improved.
65//! There is no fuzzing or corpora of X.509 certificates that we're testing against,
66//! for example.
67
68pub mod algorithm;
69pub use algorithm::{DigestAlgorithm, EcdsaCurve, KeyAlgorithm, SignatureAlgorithm};
70pub mod asn1time;
71pub mod certificate;
72pub use certificate::{
73    CapturedX509Certificate, MutableX509Certificate, X509Certificate, X509CertificateBuilder,
74};
75pub mod rfc2986;
76pub mod rfc3280;
77pub mod rfc3447;
78pub mod rfc4519;
79pub mod rfc5280;
80pub mod rfc5480;
81pub mod rfc5652;
82pub mod rfc5915;
83pub mod rfc5958;
84pub mod rfc8017;
85pub mod signing;
86pub use signing::{InMemorySigningKeyPair, KeyInfoSigner, Sign, Signature};
87#[cfg(any(feature = "test", test))]
88pub mod testutil;
89
90use thiserror::Error;
91
92pub use signature::Signer;
93
94/// Errors related to X.509 certificate handling.
95#[derive(Debug, Error)]
96pub enum X509CertificateError {
97    #[error("unknown digest algorithm: {0}")]
98    UnknownDigestAlgorithm(String),
99
100    #[error("unknown signature algorithm: {0}")]
101    UnknownSignatureAlgorithm(String),
102
103    #[error("unknown key algorithm: {0}")]
104    UnknownKeyAlgorithm(String),
105
106    #[error("unknown elliptic curve: {0}")]
107    UnknownEllipticCurve(String),
108
109    #[error("KeyAlgorithm encountered unexpected algorithm parameters: {0}")]
110    UnhandledKeyAlgorithmParameters(&'static str),
111
112    #[error("can not verify {1:?} signatures made with key algorithm {0:?}")]
113    UnsupportedSignatureVerification(KeyAlgorithm, SignatureAlgorithm),
114
115    #[error("ring rejected loading private key: {0}")]
116    PrivateKeyRejected(String),
117
118    #[error("DER error: {0}")]
119    Der(der::Error),
120
121    #[error("error when decoding ASN.1 data: {0}")]
122    Asn1Parse(bcder::decode::DecodeError<std::convert::Infallible>),
123
124    #[error("I/O error occurred: {0}")]
125    Io(#[from] std::io::Error),
126
127    #[error("error decoding PEM data: {0}")]
128    PemDecode(pem::PemError),
129
130    #[error("error creating signature: {0}")]
131    SigningError(#[from] signature::Error),
132
133    #[error("error creating cryptographic signature with memory-backed key-pair")]
134    SignatureCreationInMemoryKey,
135
136    #[error("certificate signature verification failed")]
137    CertificateSignatureVerificationFailed,
138
139    #[error("error generating key pair")]
140    KeyPairGenerationError,
141
142    #[error("RSA key generation is not supported")]
143    RsaKeyGenerationNotSupported,
144
145    #[error("target length for PKCS#1 padding to too short")]
146    PkcsEncodeTooShort,
147
148    #[error("unhandled error: {0}")]
149    Other(String),
150}
151
152impl From<der::Error> for X509CertificateError {
153    fn from(e: der::Error) -> Self {
154        Self::Der(e)
155    }
156}
157
158impl From<ring::error::KeyRejected> for X509CertificateError {
159    fn from(e: ring::error::KeyRejected) -> Self {
160        Self::PrivateKeyRejected(e.to_string())
161    }
162}
163
164impl From<bcder::decode::DecodeError<std::convert::Infallible>> for X509CertificateError {
165    fn from(e: bcder::decode::DecodeError<std::convert::Infallible>) -> Self {
166        Self::Asn1Parse(e)
167    }
168}