openssl/openssl
X.509 and PKI
Active contributors: Tomas Mraz, Dr. David von Oheimb, Pauli, Matt Caswell, Stephen Henson (historical)
Purpose
OpenSSL's X.509 stack covers everything needed to issue, parse, build, validate, and revoke RFC 5280 / RFC 6818 certificates, plus the surrounding PKI machinery: CRLs, OCSP, Certificate Transparency (RFC 6962), RFC 3161 timestamps, attribute certificates (RFC 5755 / RFC 9913), and the various extensions used in IETF, IEEE, and ITU-T profiles.
The implementation is one of the oldest and most heavily-trafficked parts of libcrypto. The verifier (crypto/x509/x509_vfy.c, ~136 KB) is the single largest file in the tree.
Directory layout
crypto/
├── x509/ -- core X.509 stack
│ ├── x_x509.c, x509_set.c, x509_lu.c, x509_vfy.c, x509_vpm.c, x509_cmp.c, x509_txt.c, x509_trust.c, x_pubkey.c
│ ├── x_crl.c, x509cset.c, x509rset.c, x509name.c, x509_obj.c
│ ├── v3_*.c -- per-extension parsers/printers (BasicConstraints, KeyUsage, SubjectAltName, AIA, CRLDistributionPoints, CertificatePolicies, NameConstraints, ProxyCert, IPAddrBlocks, AS, …)
│ ├── pcy_*.c -- the certificate policy tree (RFC 5280 §6.1.4)
│ ├── x509_acert.c -- attribute certificates
│ ├── by_dir.c, by_file.c, by_store.c -- X509_LOOKUP backends
│ └── t_*.c -- pretty-printers
├── ocsp/ -- RFC 6960 OCSP client + server-side helpers
├── ct/ -- RFC 6962 Certificate Transparency client
├── ts/ -- RFC 3161 timestamp client + server
├── pem/ -- PEM I/O for certs/keys/CRLs/CSRs
├── http/ -- minimal HTTP client used for AIA / OCSP / CRLDP / CMP
└── store/ -- the OSSL_STORE URI loader (file:, pkcs11:, …)Key types
| Type | Schema source | Purpose |
|---|---|---|
X509 |
x_x509.c |
A certificate (cert + sig + cached state). |
X509_CRL |
x_crl.c |
A Certificate Revocation List. |
X509_REQ |
x_req.c |
A PKCS#10 Certificate Signing Request. |
X509_NAME |
x_name.c |
A Name (sequence of RelativeDistinguishedName). |
X509_EXTENSION / X509V3_EXT_METHOD |
crypto/asn1/x_attrib.c + crypto/x509/v3_*.c |
Generic extension carrier + per-OID parser registry. |
X509_STORE, X509_STORE_CTX |
x509_lu.c, x509_vfy.c |
The trust store and a per-verification context. |
X509_VERIFY_PARAM |
x509_vpm.c |
Tunable verification parameters (depth, purpose, time, hostflags, …). |
X509_PUBKEY |
x_pubkey.c |
The SubjectPublicKeyInfo wrapper. |
X509_ACERT |
x509_acert.c |
An attribute certificate. |
X509_LOOKUP_METHOD |
by_dir.c, by_file.c, by_store.c |
Pluggable lookup backends for the trust store. |
Reading and writing certificates
X509 *cert = NULL;
BIO *bio = BIO_new_file("cert.pem", "r");
PEM_read_bio_X509(bio, &cert, NULL, NULL);
const ASN1_TIME *not_after = X509_get0_notAfter(cert);
const X509_NAME *subject = X509_get_subject_name(cert);
X509_print(BIO_new_fp(stdout, BIO_NOCLOSE), cert);
X509_free(cert);
BIO_free(bio);For DER input use d2i_X509_bio or d2i_X509(NULL, &p, len).
For new code, the OSSL_STORE URI loader is preferred for one-stop loading of bundles:
OSSL_STORE_CTX *s = OSSL_STORE_open("file:certs.pem", NULL, NULL, NULL, NULL);
OSSL_STORE_INFO *info;
while ((info = OSSL_STORE_load(s)) != NULL) {
if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_CERT)
handle(OSSL_STORE_INFO_get0_CERT(info));
OSSL_STORE_INFO_free(info);
}Verification
sequenceDiagram
participant App
participant Ctx as X509_STORE_CTX (x509_vfy.c)
participant Store as X509_STORE (x509_lu.c)
participant Ext as v3_*.c parsers
participant Pcy as pcy_tree.c (policies)
participant Ocsp as crypto/ocsp/
App->>Ctx: X509_STORE_CTX_init(ctx, store, leaf, untrusted_chain)
App->>Ctx: X509_verify_cert(ctx)
Ctx->>Store: X509_STORE_get_by_subject (find issuer at each step)
loop for each cert in candidate chain
Ctx->>Ctx: check signature with issuer's pubkey
Ctx->>Ext: validate every critical extension
Ctx->>Ctx: check NotBefore/NotAfter vs param-time
Ctx->>Ctx: check name constraints, key usage, ext key usage, basic constraints, path length
end
Ctx->>Pcy: build policy tree from CertificatePolicies / PolicyMappings / NameConstraints
Ctx->>Store: lookup CRL or stapled OCSP for each cert
opt CRL/OCSP attached
Ctx->>Ctx: check revocation
Ctx->>Ocsp: OCSP_basic_verify
end
Ctx-->>App: verify_cb invoked at each issue; final result via X509_STORE_CTX_get_errorThe verifier is path-discovery + path-validation. It does:
- Chain construction. Walk from the leaf to a trust anchor, considering
untrustedcerts supplied by the caller as candidates and the trust store as the source of anchors. Issuer matching uses subject/issuer DN comparison withAuthorityKeyIdentifieras a tiebreaker. - Signature validation. For each non-anchor cert, the parent's
EVP_PKEYvalidates the cert'stbsCertificatedigest+signature. - Extension validation. Every critical extension must be understood and validated; e.g.
BasicConstraints(CA flag, pathLen),KeyUsage,ExtendedKeyUsage,NameConstraints,PolicyConstraints,InhibitAnyPolicy,SubjectAltName, … - Time validation.
notBefore <= now <= notAfterfor every cert, against theX509_VERIFY_PARAM_set_timevalue (defaults to current). - Hostname / IP / email matching if requested via
X509_VERIFY_PARAM_set1_host/_ip/_email. The matcher incrypto/x509/v3_utl.cimplements wildcard rules per RFC 6125 and RFC 9525. - Policy processing if any
CertificatePoliciesextension is present; the policy tree state machine lives incrypto/x509/pcy_tree.c. - Revocation if a CRL or OCSP responder is configured.
The caller can hook in at every step via the X509_STORE_set_verify_cb() callback, which is invoked on each verified-or-failed cert with the pending error. The default callback returns 0 (failed) without modification; some applications return non-zero from the callback to ignore specific errors.
Verification options
X509_VERIFY_PARAM (in x509_vpm.c) holds the tunable knobs:
set_purpose—X509_PURPOSE_SSL_CLIENT,_SSL_SERVER,_NS_SSL_SERVER,_SMIME_SIGN,_SMIME_ENCRYPT,_CRL_SIGN,_TIMESTAMP_SIGN,_OCSP_HELPER,_ANY. Each sets the required EKU and TLS-feature checks.set_trust—X509_TRUST_SSL_CLIENT, etc.set_flags—X509_V_FLAG_CRL_CHECK,_CRL_CHECK_ALL,_X509_STRICT,_PARTIAL_CHAIN,_NO_CHECK_TIME,_USE_DELTAS,_TRUSTED_FIRST,_USE_DELTAS,_PARTIAL_CHAIN,_POLICY_CHECK,_EXPLICIT_POLICY,_INHIBIT_ANY,_INHIBIT_MAP,_NOTIFY_POLICY,_EXTENDED_CRL_SUPPORT,_NO_ALT_CHAINS,_LEGACY_VERIFY,_CHECK_SS_SIGNATURE,_CB_ISSUER_CHECK, …set_depth— max chain depth.set_auth_level— minimum security strength bits.set1_host/set1_ip/set1_email— name matching.set1_policies/set_inh_flags— policy tree controls.
Building certificates
To issue a cert, the typical code path:
X509 *crt = X509_new();
X509_set_version(crt, X509_VERSION_3);
ASN1_INTEGER_set(X509_get_serialNumber(crt), 1);
X509_gmtime_adj(X509_getm_notBefore(crt), 0);
X509_gmtime_adj(X509_getm_notAfter(crt), 365 * 24 * 3600);
X509_set_subject_name(crt, subject);
X509_set_issuer_name(crt, issuer);
X509_set_pubkey(crt, pubkey);
X509_add_ext(crt, ext_basic_constraints_ca_false, -1);
X509_add_ext(crt, ext_key_usage_dig_sig_kex, -1);
X509_add_ext(crt, ext_san, -1);
X509_sign(crt, ca_privkey, EVP_sha256());apps/openssl ca (the simple CA in apps/ca.c) and apps/openssl x509 -req -CA ... are command-line wrappers around the same machinery.
Extensions
Every standard extension has its own file crypto/x509/v3_<name>.c. The registry is in crypto/x509/v3_lib.c (X509V3_EXT_get, X509V3_EXT_add, X509V3_EXT_d2i, X509V3_EXT_i2d). The extension method has hooks for parsing from text config (X509V3_EXT_conf, X509V3_EXT_conf_nid) — this is what openssl req -extensions v3_ca -config openssl.cnf uses.
To add a new extension:
- Allocate a new
NID_<name>incrypto/objects/objects.txt, runmake update. - Write a new
v3_<name>.cwith anX509V3_EXT_METHODinstance (parser, encoder, conf parser, printer). - Register the method in
crypto/x509/standard_exts.handext_dat.h.
CRLs
X509_CRL lives in x_crl.c. Loaded the same way as certificates (PEM_read_bio_X509_CRL, d2i_X509_CRL_bio). The verifier consults the store for CRLs by issuer when X509_V_FLAG_CRL_CHECK is set; the typical lookup backend is by_dir.c which searches ~/.openssl/certs or /etc/ssl/certs-style hashed directories.
Issuing a CRL: build an X509_CRL, add X509_REVOKED entries for each revoked serial, sign with X509_CRL_sign.
OCSP
crypto/ocsp/:
ocsp_asn.c— schema (OCSP_REQUEST,OCSP_RESPONSE,OCSP_BASICRESP, …).ocsp_lib.c— request/response build helpers.ocsp_cl.c— client side: build a request from cert, parse a response.ocsp_srv.c— server side: build a response.ocsp_ext.c— OCSP-specific extensions (Nonce, AcceptableResponses, CrlReferences).ocsp_vfy.c— verify a basic OCSP response (signed by the issuer or a delegated responder with the OCSPSigning EKU).ocsp_ht.c— HTTP transport (callscrypto/http/).
The apps/openssl ocsp subcommand uses these.
Certificate Transparency
crypto/ct/ parses Signed Certificate Timestamps (SCTs) from the 1.3.6.1.4.1.11129.2.4.2 X.509 extension, OCSP responses, or the TLS extension. It validates them against a configured set of CT log public keys (CTLOG_STORE). The implementation is conservative — it only ever validates SCTs, never produces them.
Timestamps (RFC 3161)
crypto/ts/:
- Builds and parses
TimeStampReq/TimeStampResp. - Verifies that a timestamp covers a specified hash and was signed by an authorised TSA.
apps/openssl ts is the CLI front end.
Attribute Certificates
crypto/x509/x509_acert.c implements RFC 5755 / RFC 9913 attribute certificates. Same overall shape as X509 but the holder/issuer/attributes structure differs. Verification follows the same chain-construction approach, with attribute-cert-specific extension validation in v3_ac_tgt.c, v3_aaa.c, etc.
Trust store backends
X509_LOOKUP_METHOD is the abstraction for a lookup source:
by_file.c— load a single PEM bundle.by_dir.c— hashed-directory lookup (e.g.c_rehash-style).by_store.c— delegate to theOSSL_STOREURI loader (sopkcs11:-backed CAs work transparently).
X509_STORE_load_locations and X509_STORE_load_path are the convenience wrappers.
OSSL_STORE
crypto/store/ is the URI-based loader. Built-in scheme: file:. With third-party providers, pkcs11:, tpm2:, etc. become available. The result is a stream of OSSL_STORE_INFO of types CERT, CRL, NAME (alias), PUBKEY, PARAMS, PKEY.
Integration points
libsslusesX509_STORE_CTXto verify the peer chain at handshake.crypto/cms/,crypto/pkcs7/,crypto/pkcs12/all consume X509/X509_NAME/X509_EXTENSION when signing/verifying their structures.crypto/cmp/issues new certs through this stack; CRMF requests are X.509-shaped.- The Java / Python / Node.js / Erlang / Ruby / etc. bindings are mostly thin marshalling wrappers around these types.
Entry points for modification
- New extension: see "Extensions" above.
- New trust constraint or check: thread it through
x509_vfy.candX509_VERIFY_PARAMflags. - New profile / purpose: register in
crypto/x509/v3_purp.c. - New name-matching mode: extend
crypto/x509/v3_utl.c(do_x509_check).
Documentation
doc/man3/X509_verify_cert.pod,X509_STORE_CTX_new.pod,X509_VERIFY_PARAM_set_flags.pod,X509_check_host.pod.doc/man3/X509_get_extension_flags.pod— the cached extension-check state.doc/man3/PEM_read_X509.pod,d2i_X509.pod,OSSL_STORE_open.pod.doc/man3/OCSP_*.pod,TS_*.pod,CT_*.pod.doc/man7/x509.pod,ossl-guide-x509-introduction.pod.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.