cert_helper/lib.rs
1//! # Cert-Helper
2//!
3//! A lightweight helper library for managing X.509 certificates using OpenSSL.
4//! Provides convenient tools for generating Certificate Signing Requests (CSRs),
5//! Certificate Revocation Lists (CRLs), and handling private keys.
6//!
7//! ## Description
8//!
9//! A minimal wrapper combining `openssl`, `yasna`, and `x509-parser` crates
10//! to simplify common certificate operations such as creation, signing, parsing, and revocation.
11//!
12//! The package has not been reviewed for any security issues and is intended for testing purposes only.
13//!
14//! This library provides a set of utility functions to simplify common tasks such as:
15//! - Creating self-signed or CA-signed certificates
16//! - Generating RSA, ECDSA,or Ed25519 private keys, note that Ed25519 do not require any hash variant
17//! - Optionally, post-quantum signing keys (ML-DSA, SLH-DSA) behind the `pqc` Cargo feature — see [Post-Quantum keys](#post-quantum-keys-experimental)
18//! - Creating Certificate Signing Requests (CSRs)
19//! - Signing certificates from CSRs using a CA certificate and key
20//! - Reading and writing certificates, keys, and CSRs in PEM format
21//! - Validating certificate chains and properties
22//! - Create or update certificate revocation list(crl)
23//! - Note that this is a simple crl parser that only handle the fields that are included then
24//! generating a crl with this code
25//!
26//! ### Certificate Signing Requirements
27//! To sign another certificate, the signing certificate must:
28//! - Have the `CA` (Certificate Authority) flag set to `true`
29//! - Include the `KeyUsage` extension with the `keyCertSign` bit enabled
30//!
31//! These constraints ensure that the certificate is recognized as a valid CA and can be used to issue other certificates.
32//!
33//! ### Use Cases
34//! - Generating certificates for local development or internal services
35//! - Creating a simple certificate authority for testing
36//! - Validating certificate chains in custom TLS setups
37//! - Creating CSRs to be signed by external or internal CAs
38//! - Issuing signed certificates from CSRs for controlled certificate management
39//! - Create crl for testing how a client handle certificate revocations, optionally add crl reason for the revoked certificate
40//!
41//!
42//! ## Basic Example creating a certificate and private key
43//! ```rust
44//! use cert_helper::certificate::{CertBuilder, Certificate, HashAlg, KeyType, Usage, verify_cert, UseesBuilderFields};
45//!
46//! // create a self signed certificate with several optional values set
47//! let ca = CertBuilder::new()
48//! .common_name("My Test Ca")
49//! .country_name("SE")
50//! .state_province("Stockholm")
51//! .organization("my org")
52//! .locality_time("Stockholm")
53//! .is_ca(true)
54//! .key_type(KeyType::P521)
55//! .signature_alg(HashAlg::SHA512)
56//! .key_usage([Usage::certsign, Usage::crlsign].into_iter().collect());
57//! let root_cert = ca.build_and_self_sign();
58//! assert!(root_cert.is_ok())
59//! // to write data to file you need to use X509Common to access the save
60//! // ca.save("./certs/", "mytestca")?;
61//!```
62//! ## Basic Example creating a certificate signing request and private key
63//! ```rust
64//! use cert_helper::certificate::{Usage, Csr, verify_cert, UseesBuilderFields,CsrBuilder};
65//!
66//! // create a certificate signing request and private key
67//! let csr_builder = CsrBuilder::new()
68//! .common_name("example2.com")
69//! .country_name("SE")
70//! .state_province("Stockholm")
71//! .organization("My org")
72//! .locality_time("Stockholm")
73//! .alternative_names(vec!["example2.com", "www.example2.com"])
74//! .key_usage(
75//! [
76//! Usage::contentcommitment,
77//! Usage::encipherment,
78//! Usage::serverauth,
79//! ]
80//! .into_iter()
81//! .collect(),
82//! );
83//! let csr = csr_builder.certificate_signing_request();
84//! assert!(csr.is_ok());
85//!
86//! // to write data to file you need to use X509Common to access the save
87//! // csr.save("./certs/", "mytestca")?;
88//!
89//!```
90//! ## Basic Example creating a signed certificate from a signing request
91//! ```rust
92//! use cert_helper::certificate::{CertBuilder, Csr, verify_cert, UseesBuilderFields, CsrBuilder,CsrOptions};
93//!
94//! let ca = CertBuilder::new().common_name("My Test Ca").is_ca(true);
95//! let root_cert = ca.build_and_self_sign().expect("failed to create root certificate");
96//!
97//! let csr_builder = CsrBuilder::new().common_name("example2.com");
98//! let csr = csr_builder.certificate_signing_request().expect("Failed to generate csr");
99//! let options = CsrOptions::new();// used for enabling csr for CA certficates
100//! let cert = csr.build_signed_certificate(&root_cert, options);
101//! assert!(cert.is_ok());
102//! ```
103//!
104//! ## Basic Example creating a chain of signed certificates and verify the chain
105//! ```rust
106//! use cert_helper::certificate::{CertBuilder, verify_cert, UseesBuilderFields};
107//!
108//! let cert = CertBuilder::new().common_name("Cert-1").is_ca(true);
109//! let cert_1 = cert.build_and_self_sign().expect("Failed to create certificate");
110//! let cert = CertBuilder::new().common_name("Cert-2").is_ca(true);
111//! let cert_2 = cert.build_and_sign(&cert_1).expect("Failed to create certificate");
112//! let cert = CertBuilder::new().common_name("Cert-3");
113//! let cert_3 = cert.build_and_sign(&cert_2).expect("Failed to create certificate");
114//!
115//! match verify_cert(&cert_3.x509, &cert_1.x509, vec![&cert_2.x509]) {
116//! Ok(true) => println!("verify ok"),
117//! _ => println!("failed verify"),
118//! }
119//!
120//! ```
121//!
122//! ## Post-Quantum keys (experimental)
123//!
124//! Build with `--features pqc` to enable NIST-standardized post-quantum
125//! signature algorithms as new [`KeyType`](certificate::KeyType) variants:
126//!
127//! - `MlDsa44`, `MlDsa65`, `MlDsa87` — FIPS 204 (ML-DSA, formerly Dilithium)
128//! - `SlhDsaSha2_128s`, `SlhDsaSha2_192s`, `SlhDsaSha2_256s` — FIPS 205 (SLH-DSA, formerly SPHINCS+)
129//!
130//! **Runtime requirement:** OpenSSL **≥ 3.5** at build and runtime (enforced
131//! in `build.rs`). The `openssl` Rust crate does not yet expose safe high-level
132//! wrappers for these algorithms — this implementation uses `openssl-sys` FFI
133//! directly, reusing the Ed25519 digest-less signing path. Availability and
134//! stability track upstream; expect churn until safe bindings land.
135//!
136//! The following example only compiles when the `pqc` feature is enabled — it
137//! is hidden from the default doctest build and exercised by `cargo test --features pqc`.
138//!
139//! ```
140//! # #[cfg(feature = "pqc")] {
141//! use cert_helper::certificate::{CertBuilder, KeyType, UseesBuilderFields};
142//!
143//! // Self-signed CA with an ML-DSA-65 key. Same builder surface as classical keys —
144//! // the digest-less signing path and build-time OpenSSL 3.5+ check are implicit.
145//! let ca = CertBuilder::new()
146//! .common_name("My PQC CA")
147//! .is_ca(true)
148//! .key_type(KeyType::MlDsa65)
149//! .build_and_self_sign()
150//! .expect("self-sign ML-DSA-65");
151//!
152//! // PQC-signed certs are interoperable with OpenSSL's verifier; the signature
153//! // algorithm OID in the PEM will read "ML-DSA-65" (2.16.840.1.101.3.4.3.18).
154//! assert_eq!(
155//! ca.x509.issuer_name().to_der().ok(),
156//! ca.x509.subject_name().to_der().ok()
157//! );
158//! # }
159//! ```
160//!
161//! A PQC CA can also sign classical CSRs (and vice versa); see the
162//! `pqc_crl_example` and `pqc_all_variants` examples in `examples/` for full
163//! chain and CRL workflows.
164//!
165//! ## Example on how to create a certifcate revocation list(clr)
166//!
167//! Create a crl, with one revoked certificate that have CRL Reason: Key Compromise
168//!
169//! ```rust
170//! use cert_helper::certificate::{CertBuilder, UseesBuilderFields};
171//! use cert_helper::crl::{X509CrlBuilder,CrlReason,X509CrlWrapper};
172//! use chrono::Utc;
173//! use num_bigint::BigUint;
174//!
175//! let ca = CertBuilder::new()
176//! .common_name("My Test Ca")
177//! .is_ca(true)
178//! .build_and_self_sign()
179//! .unwrap();
180//! let mut builder = X509CrlBuilder::new(ca.clone());
181//! let revocked = CertBuilder::new()
182//! .common_name("My Test")
183//! .build_and_self_sign()
184//! .unwrap();
185//!
186//! let bytes = revocked.x509.serial_number().to_bn().unwrap().to_vec();
187//! builder.add_revoked_cert_with_reason(BigUint::from_bytes_be(&bytes),
188//! Utc::now(),
189//! vec![CrlReason::KeyCompromise]);
190//!
191//! let wrapper = builder.build_and_sign().unwrap();
192//! // to save crl as pem use the helper function
193//! // wrapper.save_as_pem("./certs", "crl.pem").expect("failed to save crl as pem file");
194//!
195//! // use the wrapper to check sign, revocations
196//! let result = wrapper.verify_signature(ca.x509.public_key().as_ref().unwrap());
197//! assert!(result.unwrap());
198//! let is_revoked = wrapper.revoked(revocked.x509.serial_number());
199//! assert!(is_revoked);
200//! ```
201//!
202//! ## Config
203//!
204//! Values that can be selected for building a certificate
205//! | keyword | description | options |
206//! | ----------------- | --------------------------------------------------------------------------- | ----------------------------------- |
207//! | common_name | the common name this certificate shoud have, mandatory field | string: www.foo.se |
208//! | key_type | key type to be used, defaults to RSA2048 | enum: RSA2048, RSA4096, P224, P256, P384, P521, Ed25519, and with `--features pqc`: MlDsa44, MlDsa65, MlDsa87, SlhDsaSha2_128s, SlhDsaSha2_192s, SlhDsaSha2_256s |
209//! | ca | is this certificate used to sign other certificates, default value is false | boolean: true or false |
210//! | country_name | the country code to use,must follow the standard defined by ISO 3166-1 alpha-2. | string: SE |
211//! | organization | organisation name | string: test |
212//! | state_province | some name | string: test |
213//! | locality_time | Stockholm | string: Stockholm |
214//! | alternative_names | list of alternative DNS names this certificate is valid for | string: valid dns names |
215//! | signature_alg | which algorithm to be used for signature, default is SHA256 | enum: SHA1, SHA256, SHA384, SHA512 |
216//! | valid_from | Start date then the certificate is valid, default is now | string: 2010-01-01 |
217//! | valid_to | End date then the certificate is not valid, default is 1 year | string: 2020-01-01 |
218//! | usage | Key usage to add to the certificates, see list below for options | list of enums, defined in Key Usage table |
219//!
220//! ### Key usage
221//!
222//! If CA is true the key usages to sign certificates and crl lists are added automatically.
223//!
224//! | keyword | description |
225//! | ----------------- | ---------------------------------------------------------- |
226//! | certsign | allowed to sign certificates |
227//! | crlsign | allowed to sign crl |
228//! | encipherment | allowed to enciphering private or secret keys |
229//! | clientauth | allowed to authenticate as client |
230//! | serverauth | allowed ot be used for server authenthication |
231//! | signature | allowed to perfom digital signature (For auth) |
232//! | contentcommitment | allowed to perfom document signature (prev non repudation) |
233
234pub mod certificate;
235pub mod crl;