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