synta-certificate
Table of Contents generated with DocToc
- Overview
- Features
- Parsing and zero-copy decoding
- Revocation, requests, and OCSP
- Certificate bundle formats (PKCS#7 / PKCS#12)
- PKI building (certificate, CSR, and PKCS#12 creation)
- Crypto backends (openssl and nss features)
- Name, extension, and algorithm helpers
- PEM encoding
- CMS cryptography (openssl feature)
- Protocol schema types
- Platform compatibility
- Usage
- Decoding a Certificate
- Encoding a Certificate
- Building a Certificate
- Building a CSR
- Building a PKCS#12 Archive
- Generating Keys and Signing
- Verifying a Certificate Signature
- Algorithm Identification
- DN Formatting
- Public Key Decoding
- PEM Encoding and Decoding
- Parsing a CRL
- Parsing a CSR
- Parsing an OCSP Response
- Extracting Certificates from PKCS#7 / CMS
- Extracting Certificates from PKCS#12
- Extracting Private Keys from PKCS#12
- Subject Alternative Names
- Parsing Distinguished Name Attributes
- CMS EncryptedData Encryption and Decryption
- RFC 3279 Algorithm Parameters
- Attribute Certificates (RFC 5755)
- CRMF Messages (RFC 4211)
- CMP Messages (RFC 9810)
- Encoding Extension Values
- Building a CRL
- Building an OCSP Response
- Certificate Structure
- Supported Algorithms
- Cargo Features
- Code Generation
- License
- References
X.509 certificate structures for the synta ASN.1 library.
Certificate chain verification is in the companion crate
synta-x509-verification, which implements RFC 5280 §6 path validation on top of the types provided here.
Overview
This crate provides typed X.509 v3 certificate structures based on RFC 5280. The
structures integrate directly with the synta ASN.1 encoder/decoder and are designed for
high-throughput parsing: the issuer, subject, and extensions fields are stored as
zero-copy RawDer<'a> spans — raw DER byte slices borrowed from the input buffer — so
they are decoded lazily, on demand, without any allocation at parse time.
Algorithm identification helpers return &'static str or Option<&'static str> via
direct OID component matching, with no string allocation or formatting.
Features
Parsing and zero-copy decoding
- RFC 5280 compliant — complete X.509 v3 certificate and
TBSCertificatestructures - Zero-copy parsing —
issuer,subject, andextensionsstored asRawDer<'a>byte spans;subjectPublicKeystored asBitStringRef<'a> - Lazy field decoding — Distinguished Names and extensions are decoded only when accessed, eliminating parse-time overhead
- Auto-generated from ASN.1 schemas — all types generated from formal ASN.1 definitions via
synta-codegen - Post-quantum ready — built-in support for ML-DSA (FIPS 204) and ML-KEM (FIPS 203) algorithms
Revocation, requests, and OCSP
- X.509 CRL support — parse Certificate Revocation Lists (RFC 5280 §5) via the
crlmodule - PKCS#10 CSR support — parse Certificate Signing Requests (RFC 2986) via the
csrmodule - OCSP support — parse Online Certificate Status Protocol responses (RFC 6960) via the
ocspmodule
Certificate bundle formats (PKCS#7 / PKCS#12)
- PKCS#7 / CMS certificate extraction — extract certificates from SignedData bundles (RFC 5652) via
certs_from_pkcs7 - PKCS#12 certificate extraction — extract certificates from PFX archives (RFC 7292) via
certs_from_pkcs12; optional OpenSSL backend for encrypted bags - PKCS#12 private key extraction — extract
OneAsymmetricKey(PKCS#8 / RFC 5958) blobs from PFX archives viakeys_from_pkcs12; same OpenSSL backend for encrypted bags - PKCS#8 types —
OneAsymmetricKey<'a>(RFC 5958) andPrivateKeyInfo<'a>alias generated fromasn1/PKCS8.asn1viapkcs8_typesmodule
PKI building (certificate, CSR, and PKCS#12 creation)
- Certificate building —
CertificateBuilder+CertificateSignertrait assemble and sign a complete DERCertificatewith full control over extensions, validity period, and serial number;OpensslCertificateSignerprovides an OpenSSL-backed signer - CSR building —
CsrBuilder+CertificateSignertrait produce a DERCertificationRequest(PKCS#10, RFC 2986) - CRL building —
CertificateListBuilderassembles a signedTBSCertListDER with support for revoked entries (per-entryreasonCodeextension), CRL-level extensions, and optionalnextUpdate;CertificateListBuilder::assemblesplices TBS + algorithm + signature into a completeCertificateList - OCSP response building —
OCSPResponseBuilderassembles aResponseDataDER for external signing viabuild_tbs(), thenOCSPResponseBuilder::assemblewraps it withBasicOCSPResponseand the outerOCSPResponseSEQUENCE; supportsbyNameandbyKeyresponder identities and multipleSingleResponseentries - Attribute Certificate building —
AttributeCertificateBuilderassembles anAttributeCertificateInfoTBS DER (RFC 5755) from serial, validity period, issuerGeneralNames, and holderentityName; produces only the TBS portion for external signing - CRMF message building —
CertReqMsgBuilderassembles a single RFC 4211CertReqMsgDER with subject, public key, proof-of-possession, and optional publication info;CertReqMessagesBuilderwraps a list of pre-encodedCertReqMsgblobs in the outerSEQUENCE OFenvelope;PUB_METHOD_DONT_CARE/X500/WEB/LDAPconstants select the publication method - CMP message building —
CMPMessageBuilderassembles aPKIMessageDER (RFC 9810) from sender/recipientGeneralNamevalues, optional transaction ID and nonce fields, and a body payload; body setters coverir,cr,kur,p10cr,genm, andpkiConf - PKCS#12 archive building —
Pkcs12Builderassembles a complete PFX DER from certificates and an optional private key; delegates all cryptography to aPkcs12Encryptorimpl;OpensslPkcs12Encryptorprovides PBES2/PBKDF2/AES-256-CBC encryption with a configurablePkcs12Config(iterations, cipher, PRF, and MAC algorithm)
Crypto backends (openssl and nss features)
The crate provides a backend-agnostic key and verification layer so that callers are not exposed to backend-specific types unless they need them.
Backend-agnostic abstractions (always available)
PrivateKeytrait — object-safe interface for private keys:public_key_spki_der()returns the DER-encodedSubjectPublicKeyInfo;as_signer(algorithm)returns aBox<dyn ErasedCertificateSigner>ready for use withCertificateBuilder::signPrivateKeyBuilder— factory for generating new keys without naming the backend type; choose the algorithm viaec(curve),rsa(bits),ed25519(),ed448(),ml_dsa(level), orml_kem(level), then call.generate()to obtain aBox<dyn PrivateKey>KeySpec— enum variant set used internally byPrivateKeyBuilder; also inspectable for algorithm-routing in custom key providersBackendPrivateKey— opaque PKCS#8 DER wrapper; implementsPrivateKeyand caches the parsed key for O(1)as_signer()calls; supportsfrom_pem,from_der,from_pkcs8_der_unchecked,from_ec_private_scalar(import EC key from raw scalar + affine coordinates), andfrom_rsa_private_components(import RSA key from CRT fields viaRsaPrivateComponents); exposed mainly for storage and serialisation use casesBackendPublicKey— opaque SPKI DER wrapper; backend-agnostic entry point forverify_signature(tbs, alg_id_der, sig)(dispatches to NSS whennssis enabled, otherwise OpenSSL); also exposesfrom_pem,from_der,from_rsa_components,from_ec_components,key_type(),key_bit_size(), and RSA/EC component extractionErasedCertificateSigner— object-safe variant ofCertificateSigner; returned byPrivateKey::as_signer;Box<dyn ErasedCertificateSigner>implementsCertificateSignerErasedSignatureVerifier— object-safe variant ofSignatureVerifier; returned bydefault_signature_verifier();Box<dyn ErasedSignatureVerifier>implementsSignatureVerifierdefault_signature_verifier()— returns the best available verifier: NSS whennssis enabled, otherwise OpenSSL, otherwise a stub that returns an errordefault_key_id_hasher()— analogous factory forKeyIdHasherimplementations
NSS backend (nss feature)
| Type | Description |
|---|---|
NssSignatureVerifier |
Verifies X.509 signatures via VFY_VerifyDataWithAlgorithmID; supports RSA PKCS#1 / RSA-PSS / ECDSA / EdDSA / ML-DSA |
NssVerifierError |
Error type for NssSignatureVerifier |
NssSigner |
Signs TBS blobs from a PKCS#8 private key imported into the NSS in-memory softokn slot; supports RSA / ECDSA / EdDSA / ML-DSA (Ed448 not supported in NSS ≤ 3.121) |
NssSignerError |
Error type for NssSigner |
NssKeyIdHasher |
Computes SHA-1/256/384/512 via PK11_HashBuf for SKI/AKI extension encoding |
NssKeyIdHasherError |
Error type for NssKeyIdHasher |
OpenSSL backend (openssl feature)
| Type | Description |
|---|---|
OpensslPrivateKey |
OpenSSL-backed private key implementing PrivateKey; wraps PKey<Private> |
OpensslCertificateSigner |
Implements CertificateSigner around an OpenSSL PKey<Private>; accepts hash-name string |
OpensslCertificateSignerError |
Error type for OpensslCertificateSigner |
OpensslSignatureVerifier |
Verifies X.509 signatures via OpenSSL EVP; dispatches on algorithm OID |
OpensslVerifierError |
Error type for OpensslSignatureVerifier |
OpensslKeyIdHasher |
SHA-1/256/384/512 hashing via OpenSSL for SKI/AKI extension encoding |
OpensslKeyIdHasherError |
Error type for OpensslKeyIdHasher |
Name, extension, and algorithm helpers
- RFC 4514-style DN formatting —
format_dnwalks the raw DER directly;format_dn_slashemits the openssl legacy/CN=.../O=...form used in AKI DirName output - Subject Alternative Name access —
Certificate::subject_alt_names()returns parsed SAN entries as(tag_number, content)pairs;parse_general_nameswalks any rawSEQUENCE OF GeneralNameDER span - DN attribute parsing —
parse_name_attrsextracts(dotted_oid, value_str)pairs from a raw Name DER span;decode_string_valuedecodes individual ASN.1 string values by tag, with Latin-1 normalisation for TeletexString - Zero-alloc OID identification —
identify_signature_algorithmandidentify_public_key_algorithmreturn static strings - Public key decoding —
decode_public_key_infodispatches on the algorithm OID and returns aPublicKeyInfoenum with algorithm-specific fields (RSA modulus/exponent, EC curve metadata) - PKCS#9 OID constants — 9 attribute OIDs from RFC 2985, RFC 5652, RFC 2986, and RFC 7292 exposed in
oids(PKCS9_EMAIL_ADDRESS,PKCS9_CONTENT_TYPE,PKCS9_MESSAGE_DIGEST,PKCS9_SIGNING_TIME,PKCS9_COUNTERSIGNATURE,PKCS9_CHALLENGE_PASSWORD,PKCS9_EXTENSION_REQUEST,PKCS9_FRIENDLY_NAME,PKCS9_LOCAL_KEY_ID) - Extension value builders (
ext_builder) — DER-encoding helpers for common X.509 v3 extension values; each returns the raw bytes of the extension'sextnValue:encode_basic_constraints(ca, path_length)— RFC 5280 §4.2.1.9encode_key_usage(bits)— RFC 5280 §4.2.1.3;KEY_USAGE_*constants map named bitsencode_subject_key_identifier(spki_der, method, hasher)— RFC 5280 §4.2.1.2 / RFC 7093encode_authority_key_identifier(issuer_spki_der, method, hasher)— RFC 5280 §4.2.1.1 / RFC 7093KeyIdMethodenum selects the key identifier algorithm:Rfc5280Sha1(default) or four RFC 7093 alternatives (SHA-256/384/512 with optional truncation, or hash of fullSubjectPublicKeyInfo)KeyIdHashertrait decouples hash computation from extension encoding;OpensslKeyIdHasherprovides an OpenSSL-backed implementation (requiresopensslfeature)- Fluent extension builders — accumulate entries and produce the final
extnValueDER onbuild():SubjectAlternativeNameBuilder— Subject Alternative Name (2.5.29.17); supportsdns_name,rfc822_name,uri,ip_address,directory_name,registered_idIssuerAlternativeNameBuilder— Issuer Alternative Name (2.5.29.18); sameGeneralNamemethods as SAN builderAuthorityInformationAccessBuilder— Authority Information Access (1.3.6.1.5.5.7.1.1);ocsp(uri)andca_issuers(uri)methodsExtendedKeyUsageBuilder— Extended Key Usage (2.5.29.37); convenience methods forserver_auth,client_auth,code_signing,email_protection,time_stamping,ocsp_signing;add_oidfor custom purposesNameConstraintsBuilder— Name Constraints (2.5.29.30);permit_dns/rfc822/uri/ip/directory_nameandexclude_*counterpartsCRLDistributionPointsBuilder— CRL Distribution Points (2.5.29.31);full_name_uri,full_name_dns,full_name_directoryIssuingDistributionPointBuilder— Issuing Distribution Point (2.5.29.28);full_name_uri,full_name_dns, boolean flagsonly_contains_user_certs,only_contains_cacerts,indirect_crl,only_contains_attribute_certsCertificatePoliciesBuilder— Certificate Policies (2.5.29.32);add_policy(oid)andadd_policy_cps(oid, uri)with CPS qualifier
PEM encoding
- PEM encoder/decoder — dependency-free
pem_to_der/der_to_pem(RFC 7468); no external crate required
CMS cryptography (openssl feature)
- CMS EncryptedData —
OpensslEncryptor/OpensslDecryptorimplement theCmsEncryptor/Decryptortraits; produce or decrypt RFC 5652 §8EncryptedDataDER with AES-CBC and a random IV - CMS EnvelopedData —
create_enveloped_dataencrypts plaintext for one or more recipients in one call (RSA-OAEP or RSA PKCS#1 v1.5 key wrap, AES-CBC content encryption);prepare_enveloped_dataperforms the same crypto but returns a pre-loadedEnvelopedDataBuilderso the caller can attachOriginatorInfocertificates/CRLs orUnprotectedAttributesbefore calling.build() - EnvelopedDataBuilder — backend-agnostic RFC 5652 §6
EnvelopedDataassembler; takes pre-computed DER for the CEK algorithm, ciphertext, and eachRecipientInfo; supportsOriginatorInfocerts/CRLs andUnprotectedAttributes;RecipientInfosSET is sorted lexicographically per X.690 §11.6 BlockCipherProvider::aes_gcm_encrypt/aes_gcm_decrypt— AES-GCM (AEAD) authenticated encryption and decryption via the active crypto backend; key is 16, 24, or 32 bytes; nonce is 12 bytes; output isciphertext ‖ 16-byte tag; optional additional authenticated data (AAD); available throughdefault_block_cipher_provider()without naming the backend type
Protocol schema types
- RFC 3279 algorithm parameters — DSA/DH domain parameters, DSA/ECDSA signature values, and EC domain parameter types (
DssParms,EcdsaSigValue,EcParameters) inpkixalgs_types - Attribute Certificate v2 — complete RFC 5755 AC structure (
AttributeCertificate,Holder,AttCertIssuer,IetfAttrSyntax,RoleSyntax,Clearance,AAControls,Targets) inattribute_cert_types;AttributeCertificateBuilderbuilds theAttributeCertificateInfoTBS DER - CRMF types — RFC 4211 Certificate Request Message Format (
CertReqMessages,CertTemplate,ProofOfPossession,POPOSigningKey,EncryptedKey,PKIArchiveOptions) incrmf_types;CertReqMsgBuilderandCertReqMessagesBuilderprovide fluent construction - CMP v3 types — RFC 9810 Certificate Management Protocol (
PKIMessage,PKIHeader,PKIBody,PKIStatusInfo,CertRepMessage, KEM-based MAC types, CA key update types) incmp_types;CMPMessageBuilderassembles completePKIMessageDER
Platform compatibility
- Python bindings — all pyo3 wrappers live in the
synta-pythoncrate;synta-certificateitself has no PyO3 dependency - no_std support — works in embedded and constrained environments with the
allocfeature
Usage
Add to your Cargo.toml:
[]
= "0.1"
= "0.1"
Decoding a Certificate
use ;
use Certificate;
let der_bytes: & = /* DER-encoded certificate */;
let mut decoder = new;
let cert: Certificate = decoder.decode?;
// serial_number is decoded eagerly
println!;
// issuer and subject are stored as RawDer<'a> — raw DER bytes, zero-copy
let issuer_der: & = cert.tbs_certificate.issuer.as_bytes;
// format_dn walks the raw DER directly; no intermediate allocation
use format_dn;
let subject_str = format_dn;
println!;
Encoding a Certificate
use ;
use ;
let cert = Certificate ;
let mut encoder = new;
encoder.encode?;
let der_bytes = encoder.finish?;
Building a Certificate
CertificateBuilder assembles a TBSCertificate, calls a CertificateSigner to obtain
the signature, then wraps the result in a Certificate SEQUENCE.
The recommended approach uses the backend-agnostic PrivateKeyBuilder so no
backend-specific types appear in caller code:
use Integer;
use ;
use Time;
let key = ec.generate
.expect;
let spki_der = key.public_key_spki_der.expect;
let signer = key.as_signer;
let cert_der: = new
.issuer_name
.subject_name
.public_key_der
.serial_number
.not_valid_before
.not_valid_after
.sign
.expect;
When you already hold an OpenSSL PKey, OpensslCertificateSigner (requires
the openssl feature) can be used directly:
use ;
let pkey: PKey = /* existing OpenSSL private key */;
let signer = new;
let cert_der: = new
.issuer_name
.subject_name
.public_key_der
.serial_number
.not_valid_before
.not_valid_after
.sign
.expect;
Building a CSR
CsrBuilder assembles a CertificationRequestInfo, signs it, and returns a
DER CertificationRequest (PKCS#10, RFC 2986). It reuses the CertificateSigner
trait, so any signer that works for certificates works here too:
use ;
let subject_der: & = /* DER-encoded Name SEQUENCE */;
let spki_der: & = /* DER-encoded SubjectPublicKeyInfo */;
let pkey: PKey = /* OpenSSL private key */;
let signer = new;
let csr_der: = new
.subject_name
.public_key_der
.sign
.expect;
Building a PKCS#12 Archive
Pkcs12Builder assembles a PFX DER from one or more certificate DER blobs and an
optional private key, delegating all cryptography to a Pkcs12Encryptor.
OpensslPkcs12Encryptor (requires the openssl feature) uses PBES2/PBKDF2-SHA256
and AES-256-CBC with 600,000 iterations by default:
use ;
let cert_der: = /* DER-encoded certificate */;
let key_der: = /* DER-encoded PKCS#8 private key */;
let password = b"s3cr3t";
let pfx_der: = new
.certificate
.private_key
.build
.expect;
write.unwrap;
Without the openssl feature, pass &NoPkcs12Encryptor to produce an
unencrypted archive (password must be empty):
use ;
let pfx_der: = new
.certificate
.build
.expect;
Generating Keys and Signing
PrivateKeyBuilder generates keys through the active crypto backend without exposing
backend-specific types. The returned Box<dyn PrivateKey> works with CertificateBuilder
via the ErasedCertificateSigner blanket impl:
use ;
use Time;
use Integer;
// Generate a new P-256 key (uses OpenSSL when that feature is enabled).
let key = ec.generate
.expect;
// The public half is returned as DER-encoded SubjectPublicKeyInfo.
let spki_der = key.public_key_spki_der
.expect;
// Create a signer — "sha256" selects the hash; ignored for EdDSA keys.
let signer = key.as_signer;
let cert_der: = new
.issuer_name
.subject_name
.public_key_der
.serial_number
.not_valid_before
.not_valid_after
.sign
.expect;
Other key types follow the same pattern:
// RSA-3072
let rsa_key = rsa.generate?;
// Ed25519 (hash-algorithm argument to as_signer is ignored)
let ed_key = ed25519.generate?;
// Post-quantum ML-DSA-65 (requires OpenSSL 3.5+ or NSS)
let pqc_key = ml_dsa.generate?;
// Composite ML-DSA-65 + ECDSA-P256-SHA512 (sub-arc 45)
// Requires openssl + pqc features (OpenSSL 3.3+) or the nss feature.
let comp_key = composite_ml_dsa.generate?;
BackendPrivateKey can be used instead when you need to load, store, or
inspect PKCS#8 bytes:
use BackendPrivateKey;
// Load from unencrypted PKCS#8 DER (requires openssl feature for parsing)
let key = from_der?;
// Load from PEM (optionally password-protected)
let key = from_pem?;
let key = from_pem?;
// Access the raw PKCS#8 DER for storage
let pkcs8_bytes: & = /* key.pkcs8_der is pub(crate); use from_pkcs8_der_unchecked to
round-trip if you already hold validated bytes */;
Verifying a Certificate Signature
BackendPublicKey::verify_signature dispatches to NSS (when the nss feature is
enabled) or OpenSSL, so the same call works with either backend:
use ;
use ;
use Encode as _;
// Parse the issuer certificate to extract its public key.
let issuer_der = read.unwrap;
let mut dec = new;
let issuer: Certificate = dec.decode.unwrap;
// Wrap the SPKI DER in a BackendPublicKey.
let mut spki_enc = new;
issuer.tbs_certificate.subject_public_key_info
.encode.unwrap;
let spki_der = spki_enc.finish.unwrap;
let pub_key = from_spki_der;
// Parse the certificate to verify.
let cert_der = read.unwrap;
let mut dec = new;
let cert: Certificate = dec.decode.unwrap;
// Re-encode the TBSCertificate and AlgorithmIdentifier for raw DER bytes.
let mut tbs_enc = new;
cert.tbs_certificate.encode.unwrap;
let tbs_der = tbs_enc.finish.unwrap;
let mut alg_enc = new;
cert.signature_algorithm.encode.unwrap;
let alg_der = alg_enc.finish.unwrap;
let sig_bytes = cert.signature_value.as_bytes;
pub_key
.verify_signature
.expect;
For use cases that do not hold a BackendPublicKey, default_signature_verifier()
returns a boxed ErasedSignatureVerifier backed by whichever backend is active:
use default_signature_verifier;
use SignatureVerifier as _;
let verifier = default_signature_verifier;
verifier.verify_certificate_signature?;
Algorithm Identification
identify_signature_algorithm and identify_public_key_algorithm use two-level integer
dispatch: a length+prefix check selects the algorithm family, then a u32 match selects
the variant. All discriminant values are derived from the generated oids constants via
const-indexing. The functions never allocate and return &'static str.
use ObjectIdentifier;
use ;
let oid = new.unwrap;
assert_eq!;
let oid = new.unwrap;
assert_eq!;
let oid = new.unwrap;
assert_eq!;
DN Formatting
format_dn formats a DER-encoded Name as a comma-space-separated string,
matching the openssl x509 -text output style:
use format_dn;
// Takes raw DER bytes of a Name (e.g. from RawDer::as_bytes())
let dn_string = format_dn;
// → "CN=example.com, O=Example Inc, C=US"
format_dn_slash produces the openssl legacy slash-prefix form used for
DirName values inside Authority Key Identifier and Subject Alt Name:
use format_dn_slash;
let dirn = format_dn_slash;
// → "/C=US/O=Example Inc/CN=example.com"
Public Key Decoding
decode_public_key_info inspects the algorithm OID and returns a
PublicKeyInfo enum with algorithm-specific fields, so callers do not
need to repeat OID dispatch for display or further processing:
use ;
let spki = &cert.tbs_certificate.subject_public_key_info;
let info = decode_public_key_info;
match info
PEM Encoding and Decoding
pem_to_der decodes every -----BEGIN ...----- block in a byte slice and
returns the DER bytes for each. der_to_pem encodes DER bytes as a single
PEM block with a caller-supplied label. Neither function depends on any
external crate.
use ;
// Decode: may contain multiple blocks (e.g. a certificate chain)
let pem_bytes = read.unwrap;
let ders: = pem_to_der;
// Encode: standard RFC 7468 format, 64-char lines
let pem_output = der_to_pem;
write.unwrap;
Common labels: "CERTIFICATE", "CERTIFICATE REQUEST", "X509 CRL",
"OCSP RESPONSE".
Parsing a CRL
The crl module exposes CertificateList (RFC 5280 §5):
use ;
use CertificateList;
let der = read.unwrap;
let mut dec = new;
let crl: CertificateList = dec.decode.unwrap;
let tbs = &crl.tbs_cert_list;
println!;
println!;
let revoked = tbs.revoked_certificates.as_ref.map_or;
println!;
Parsing a CSR
The csr module exposes CertificationRequest (RFC 2986 / PKCS#10):
use ;
use CertificationRequest;
let der = read.unwrap;
let mut dec = new;
let csr: CertificationRequest = dec.decode.unwrap;
let info = &csr.certification_request_info;
println!;
println!;
Parsing an OCSP Response
The ocsp module exposes OCSPResponse (RFC 6960):
use ;
use OCSPResponse;
let der = read.unwrap;
let mut dec = new;
let resp: OCSPResponse = dec.decode.unwrap;
println!;
if let Some = &resp.response_bytes
Extracting Certificates from PKCS#7 / CMS
certs_from_pkcs7 extracts DER-encoded certificates from a PKCS#7
SignedData bundle (RFC 5652). Both DER and BER input are accepted:
use certs_from_pkcs7;
let p7b = read.unwrap;
let certs: = certs_from_pkcs7.unwrap;
println!;
Extracting Certificates from PKCS#12
certs_from_pkcs12 extracts DER-encoded certificates from a PKCS#12 PFX
archive (RFC 7292). Pass NoCrypto to reject encrypted bags:
use ;
let pfx = read.unwrap;
let certs: = certs_from_pkcs12.unwrap;
Enable the openssl feature to decrypt bags encrypted with PBES2/PBKDF2 + AES
or legacy RC2/3DES algorithms (with deprecated-pkcs12-algorithms):
[]
= { = "0.1", = ["openssl"] }
use ;
let pfx = read.unwrap;
let certs = certs_from_pkcs12.unwrap;
Extracting Private Keys from PKCS#12
keys_from_pkcs12 extracts OneAsymmetricKey (PKCS#8, RFC 5958) blobs from a PKCS#12
PFX archive. It follows the same decryptor pattern as certs_from_pkcs12:
use ;
let pfx = read.unwrap;
let keys: = keys_from_pkcs12.unwrap;
println!;
Enable the openssl feature for bags encrypted with PBES2/PBKDF2 + AES:
use ;
let pfx = read.unwrap;
let keys = keys_from_pkcs12.unwrap;
Subject Alternative Names
Certificate::subject_alt_names() locates the SAN extension (OID 2.5.29.17) and
returns parsed GeneralName entries as (tag_number, content) pairs. Returns an
empty Vec when no SAN extension is present.
Tag numbers follow the GeneralName CHOICE (RFC 5280 §4.2.1.6):
| Tag | Alternative | Content |
|---|---|---|
| 0 | otherName |
OtherName value bytes |
| 1 | rfc822Name |
IA5String bytes (email) |
| 2 | dNSName |
IA5String bytes (DNS name) |
| 4 | directoryName |
Complete Name SEQUENCE TLV |
| 6 | uniformResourceIdentifier |
IA5String bytes (URI) |
| 7 | iPAddress |
4 bytes (IPv4) or 16 bytes (IPv6) |
| 8 | registeredID |
OID value bytes |
use ;
use Certificate;
let der = read.unwrap;
let mut dec = new;
let cert: Certificate = dec.decode.unwrap;
for in cert.subject_alt_names
parse_general_names does the same walk on any raw SEQUENCE OF GeneralName
DER span, e.g. an extension value retrieved by OID:
use parse_general_names;
// san_der is the DER bytes of a SEQUENCE OF GeneralName
let san_der: = read.unwrap;
for in parse_general_names
Parsing Distinguished Name Attributes
parse_name_attrs walks a raw Name DER span and returns one (dotted_oid, value_str)
pair per AttributeTypeAndValue. String values are decoded per-tag (TeletexString →
Latin-1, BMP/Universal → UTF-16 BE → UTF-8); unrecognised tags produce a #hexstring.
use ;
use ;
let der = read.unwrap;
let mut dec = new;
let cert: Certificate = dec.decode.unwrap;
// issuer and subject are RawDer<'a>; as_bytes() returns the Name TLV
let attrs = parse_name_attrs;
for in &attrs
// e.g.: "2.5.4.3 = example.com", "2.5.4.10 = Example Inc", "2.5.4.6 = US"
decode_string_value decodes a single value field given its tag number and raw
value bytes (tag + length already stripped):
use decode_string_value;
// tag 12 = UTF8String, 19 = PrintableString, 20 = TeletexString, 22 = IA5String
let s = decode_string_value;
assert_eq!;
CMS EncryptedData Encryption and Decryption
OpensslEncryptor implements both Encryptor (raw AES-CBC) and CmsEncryptor
(full RFC 5652 §8 EncryptedData DER assembly). A fresh random IV is generated
for every call via openssl::rand::rand_bytes.
use ;
use ;
use Encode as _;
let key: = *b"0123456789abcdef";
let plaintext = b"secret payload";
// Encrypt → DER-encoded EncryptedData SEQUENCE
let der = OpensslEncryptor
.create_encrypted_data
.expect;
// Decrypt: decode the EncryptedData, re-encode AlgorithmIdentifier to
// DER bytes, then call OpensslDecryptor.decrypt.
let mut decoder = new;
let ed: = decoder.decode.unwrap;
let mut alg_enc = new;
ed.encrypted_content_info
.content_encryption_algorithm
.encode
.unwrap;
let alg_der = alg_enc.finish.unwrap;
let ciphertext = ed.encrypted_content_info.encrypted_content
.as_ref
.unwrap
.as_bytes;
let recovered = OpensslDecryptor
.decrypt
.expect;
assert_eq!;
The Encryptor trait can also be used directly, returning (alg_id_der, ciphertext)
without the EncryptedData wrapper — useful when building custom CMS structures:
use ;
let key = ;
let = OpensslEncryptor
.encrypt
.expect;
// alg_id_der: DER AlgorithmIdentifier with embedded random IV
// ciphertext: raw AES-256-CBC ciphertext bytes
let _ = ;
RFC 3279 Algorithm Parameters
The pkixalgs_types module provides DSA/DH domain parameter types, DSA/ECDSA
signature value types, and the EC domain parameter CHOICE as defined in RFC 3279
and X9.62. The module is standalone — it does not depend on other X.509 types.
use ;
use ;
use Integer;
// Round-trip: encode a DssParms struct, then decode it back
let parms = DssParms ;
let mut enc = new;
parms.encode.unwrap;
let der = enc.finish.unwrap;
let mut dec = new;
let decoded: DssParms = dec.decode.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
// ECDSA signature value (r, s integers over the curve order)
let sig = EcdsaSigValue ;
let mut enc = new;
sig.encode.unwrap;
let sig_der = enc.finish.unwrap;
let mut dec = new;
let decoded_sig: EcdsaSigValue = dec.decode.unwrap;
assert_eq!;
// ECParameters is a CHOICE: namedCurve OID, explicit domain, or implicitlyCA
// namedCurve is the common case in modern X.509 (P-256 = 1.2.840.10045.3.1.7)
let curve_oid = new.unwrap;
let params = NamedCurve;
let mut enc = new;
params.encode.unwrap;
let params_der = enc.finish.unwrap;
let mut dec = new;
let decoded_params: = dec.decode.unwrap;
assert!;
Attribute Certificates (RFC 5755)
The attribute_cert_types module provides the full RFC 5755 Attribute
Certificate v2 structure. An Attribute Certificate (AC) binds attributes
(roles, clearances, service identifiers) to a holder without re-issuing the
holder's Public Key Certificate.
use ;
use ;
CRMF Messages (RFC 4211)
The crmf_types module provides Certificate Request Message Format types from
RFC 4211. CRMF is used in CMP (Certificate Management Protocol) to carry
certificate requests together with proof-of-possession evidence.
use ;
use ;
CMP Messages (RFC 9810)
The cmp_types module provides Certificate Management Protocol v3 types from
RFC 9810. CMP is used for automated certificate lifecycle management between
end entities and CAs.
use ;
use ;
Encoding Extension Values
encode_basic_constraints, encode_key_usage, encode_subject_key_identifier, and
encode_authority_key_identifier each return the raw DER bytes of the extension's
extnValue — the content that goes inside the OCTET STRING wrapper in the Extension
SEQUENCE. All functions use the code-generated ASN.1 types from the included X.509 schema
and synta's Encode / Decode traits; no custom DER byte manipulation is required.
For multi-entry extensions, fluent builders are available:
SubjectAlternativeNameBuilder, IssuerAlternativeNameBuilder,
AuthorityInformationAccessBuilder, ExtendedKeyUsageBuilder,
NameConstraintsBuilder, CRLDistributionPointsBuilder,
IssuingDistributionPointBuilder, and CertificatePoliciesBuilder.
Each follows the same consume-and-return pattern: chain setter calls and
finish with .build() to obtain the extnValue DER bytes.
The key-identifier functions require a KeyIdHasher implementation. Pass &OpensslKeyIdHasher
(requires the openssl feature) for SHA-1/256/384/512 support:
[]
= { = "0.1", = ["openssl"] }
use ;
// BasicConstraints for an end-entity certificate (cA absent, empty SEQUENCE)
let ee_bc = encode_basic_constraints;
assert_eq!;
// BasicConstraints for a CA with pathLen = 0
let ca_bc = encode_basic_constraints;
assert_eq!;
// KeyUsage: keyCertSign | cRLSign → BIT STRING 03 02 01 06
let ku = encode_key_usage;
assert_eq!;
// SubjectKeyIdentifier from a SubjectPublicKeyInfo DER blob
// Method: RFC 5280 default (SHA-1 of the BIT STRING value of subjectPublicKey)
let spki_der: & = /* ... */;
let ski = encode_subject_key_identifier.expect;
// AuthorityKeyIdentifier using RFC 7093 method 1:
// SHA-256 of the BIT STRING value, truncated to 160 bits
let aki = encode_authority_key_identifier.expect;
KeyIdMethod selects the hash algorithm and input data for key identifier computation:
| Variant | Hash | Input | Output | Specification |
|---|---|---|---|---|
Rfc5280Sha1 |
SHA-1 | BIT STRING value of subjectPublicKey |
20 bytes | RFC 5280 §4.2.1.2 |
Rfc7093Method1Sha256 |
SHA-256 | BIT STRING value of subjectPublicKey |
first 20 bytes | RFC 7093 §2 m1 |
Rfc7093Method2Sha384 |
SHA-384 | BIT STRING value of subjectPublicKey |
first 20 bytes | RFC 7093 §2 m2 |
Rfc7093Method3Sha512 |
SHA-512 | BIT STRING value of subjectPublicKey |
first 20 bytes | RFC 7093 §2 m3 |
Rfc7093Method4 { algorithm_oid } |
configurable | full SubjectPublicKeyInfo DER |
full hash output | RFC 7093 §2 m4 |
KeyIdHasher is a public trait so callers can plug in any hash backend:
use ;
;
Building a CRL
CertificateListBuilder assembles a TBSCertList DER for external signing.
After signing, CertificateListBuilder::assemble splices the TBS, algorithm
identifier, and signature into a complete CertificateList:
use CertificateListBuilder;
// issuer_der: DER-encoded Name SEQUENCE (e.g. from a CA certificate)
// sha256_rsa_alg_der: DER-encoded SHA256withRSA AlgorithmIdentifier
let tbs_der = new
.issuer
.this_update
.next_update
.signature_algorithm
.revoke // keyCompromise
.build
.expect;
// Sign tbs_der with your key, then assemble:
let crl_der = assemble
.expect;
The reason argument to revoke is optional; pass None to omit the
reasonCode CRL entry extension. Use add_crl_extension for CRL-level
extensions (e.g. crlNumber, authorityKeyIdentifier).
Building an OCSP Response
OCSPResponseBuilder assembles a ResponseData DER for external signing via
build_tbs(). OCSPResponseBuilder::assemble produces the complete
OCSPResponse SEQUENCE (including BasicOCSPResponse and
id-pkix-ocsp-basic wrapping):
use ;
let tbs_der = new
.responder_key_hash // byKey identity
.produced_at
.add_response
.build_tbs
.expect;
// Sign tbs_der with your OCSP responder key, then assemble:
let ocsp_der = assemble
.expect;
Use responder_name(name_der) instead of responder_key_hash to set a
byName responder identity from a DER-encoded Name SEQUENCE.
Certificate Structure
Core Types
| Type | Description |
|---|---|
Certificate<'a> |
Top-level X.509 certificate (lifetime bound to input buffer) |
TBSCertificate<'a> |
To-be-signed certificate data |
AlgorithmIdentifier<'a> |
Algorithm OID with optional parameters |
SubjectPublicKeyInfo<'a> |
Public key algorithm and key bits |
PublicKeyInfo |
Decoded public key — Rsa { modulus, exponent, bit_count }, Ec { ... }, or Unknown |
Validity |
notBefore / notAfter validity period |
Time |
CHOICE of UTCTime or GeneralizedTime |
Key Field Types
| Field | Rust type | Notes |
|---|---|---|
tbs_certificate.issuer |
RawDer<'a> |
Zero-copy; raw DER bytes of the Name SEQUENCE |
tbs_certificate.subject |
RawDer<'a> |
Zero-copy; raw DER bytes of the Name SEQUENCE |
tbs_certificate.extensions |
Option<RawDer<'a>> |
Zero-copy; decoded lazily |
subject_public_key_info.subject_public_key |
BitStringRef<'a> |
Zero-copy; borrowed key bits |
tbs_certificate.serial_number |
Integer |
Eagerly decoded |
tbs_certificate.version |
Option<Integer> |
Eagerly decoded |
signature_algorithm.algorithm |
ObjectIdentifier |
Eagerly decoded |
Type Aliases
| Alias | Underlying type | RFC 5280 name |
|---|---|---|
Version |
Integer |
Version |
CertificateSerialNumber |
Integer |
CertificateSerialNumber |
UniqueIdentifier |
BitString |
UniqueIdentifier |
Supported Algorithms
Signature Algorithms
| Algorithm | OID prefix | Standard |
|---|---|---|
| RSA (PKCS #1) | 1.2.840.113549.1.1.* | RFC 3279 |
| ECDSA | 1.2.840.10045.4.* | RFC 5480 |
| EdDSA (Ed25519) | 1.3.101.112 | RFC 8410 |
| EdDSA (Ed448) | 1.3.101.113 | RFC 8410 |
| ML-DSA-44/65/87 | 2.16.840.1.101.3.4.3.17–19 | FIPS 204 |
| Composite ML-DSA (18 variants) | 1.3.6.1.5.5.7.6.37–54 | draft-ietf-lamps-pq-composite-sigs-19 |
| DSA | 1.2.840.10040.4.* | FIPS 186 |
Public Key Algorithms
| Algorithm | Standard |
|---|---|
| RSA | RFC 3279 |
| ECDSA | RFC 5480 |
| EdDSA (Ed25519, Ed448) | RFC 8410 |
| ML-DSA (44, 65, 87) | FIPS 204 |
| Composite ML-DSA (18 variants) | draft-ietf-lamps-pq-composite-sigs-19 |
| ML-KEM (512, 768, 1024) | FIPS 203 |
| DSA | FIPS 186 |
Cargo Features
| Feature | Default | Description |
|---|---|---|
std |
yes | Standard library support |
alloc |
no | Allocation support for no_std environments |
derive |
yes | Enable derive macros for Encode/Decode traits |
serde |
no | Derive Serialize/Deserialize on generated types |
openssl |
yes | OpenSSL crypto backend: private key generation (PrivateKeyBuilder, BackendPrivateKey), certificate signing (OpensslCertificateSigner, OpensslPrivateKey), signature verification (OpensslSignatureVerifier), key-identifier hashing (OpensslKeyIdHasher), CMS encryption/decryption (OpensslEncryptor, OpensslDecryptor), and encrypted PKCS#12 (OpensslPkcs12Encryptor) |
pqc |
no | Enable post-quantum composite ML-DSA algorithms (KeySpec::CompositeMlDsa, PrivateKeyBuilder::composite_ml_dsa) and standalone ML-DSA/ML-KEM key generation via native-ossl (requires openssl feature and OpenSSL 3.3+ for composite, OpenSSL 3.5+ for standalone). Also activates cfg(ossl_mldsa) guards in the OpenSSL backend |
nss |
no | NSS crypto backend: signature verification (NssSignatureVerifier), certificate signing (NssSigner), key-identifier hashing (NssKeyIdHasher). Takes priority over openssl when both are enabled. Use --no-default-features --features nss to select NSS as the sole backend. Requires libnss3 at build and runtime. Supports composite ML-DSA signing and verification without the pqc feature flag, subject to NSS limitations: SHAKE256 variants (sub-arc 51) unsupported for signing and verification; Brainpool curve variants (sub-arcs 47, 50) unsupported for signing and verification |
deprecated-pkcs12-algorithms |
no | Support legacy 3DES and RC2 PKCS#12 encryption; requires openssl |
no_std Usage
[]
= { = "0.1", = false, = ["alloc"] }
Code Generation
All ASN.1 types are auto-generated during build time from formal schemas in the
workspace asn1/ directory using synta-codegen. To regenerate:
| Schema file | Generated module | Standard |
|---|---|---|
asn1/X509-Certificate.asn1 |
crate root (Certificate, TBSCertificate, …) |
RFC 5280 §4 |
asn1/X509-CRL.asn1 |
crl (CertificateList, TBSCertList, IssuingDistributionPoint, …) |
RFC 5280 §5 |
asn1/PKCS10-CSR.asn1 |
csr (CertificationRequest, …) |
RFC 2986 |
asn1/OCSP.asn1 |
ocsp (OCSPResponse, BasicOCSPResponse, …) |
RFC 6960 |
asn1/PKCS7-CMS.asn1 |
pkcs7_types |
RFC 5652 |
asn1/PKCS12.asn1 |
pkcs12_types |
RFC 7292 |
asn1/PKCS8.asn1 |
pkcs8_types (OneAsymmetricKey, PrivateKeyInfo) |
RFC 5958 |
asn1/PKCS9.asn1 |
pkcs9_types (OID constants for PKCS#9 attributes) |
RFC 2985, RFC 5652 §11 |
asn1/PKIXAlgs.asn1 |
pkixalgs_types (DssParms, DssSigValue, EcdsaSigValue, ECParameters, OID constants) |
RFC 3279 |
asn1/AttributeCertificate.asn1 |
attribute_cert_types (AttributeCertificate, Holder, AttCertIssuer, IetfAttrSyntax, RoleSyntax, Clearance, AAControls, Targets) |
RFC 5755 |
asn1/CRMF.asn1 |
crmf_types (CertReqMessages, CertTemplate, ProofOfPossession, POPOSigningKey, EncryptedKey, PKIArchiveOptions) |
RFC 4211 |
asn1/CMP.asn1 |
cmp_types (PKIMessage, PKIHeader, PKIBody, PKIStatusInfo, CertRepMessage, KEM MAC types, CA key update types) |
RFC 9810 |
The build.rs post-processor applies additional patches (e.g. StringTypeMode::Borrowed
for zero-copy types, extensions pattern fixup) after synta-codegen runs.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
References
- RFC 5280 — Internet X.509 PKI Certificate and CRL Profile
- RFC 7093 — Additional Methods for Generating Key Identifiers Values
- RFC 2986 — PKCS#10: Certification Request Syntax Specification
- RFC 6960 — Online Certificate Status Protocol (OCSP)
- RFC 5652 — Cryptographic Message Syntax (CMS / PKCS#7)
- RFC 7292 — PKCS#12: Personal Information Exchange Syntax
- RFC 7468 — Textual Encodings of PKIX Structures (PEM)
- RFC 8410 — Algorithm Identifiers for Ed25519 and Ed448
- FIPS 204 — ML-DSA (Module-Lattice Digital Signature Standard)
- FIPS 203 — ML-KEM (Module-Lattice Key-Encapsulation Mechanism Standard)
- RFC 3279 — Algorithms and Identifiers for the Internet X.509 PKI Certificate and CRL Profile
- RFC 5755 — An Internet Attribute Certificate Profile for Authorization
- RFC 4211 — Internet X.509 PKI Certificate Request Message Format (CRMF)
- RFC 9810 — Internet X.509 PKI Certificate Management Protocol (CMP) v3
- RFC 9629 — Using Key Encapsulation Mechanism (KEM) Algorithms in the CMS
- RFC 5958 — Asymmetric Key Packages (PKCS #8 / OneAsymmetricKey)
- RFC 2985 — PKCS #9: Selected Object Classes and Attribute Types Version 2.0