Bridge SSL

What is an X.509 certificate? Fields, format and uses

10 min readUpdated

An X.509 certificate is a data structure that binds a public key to a subject, such as a domain name, and a certificate authority signs it to assert that binding [1]. The format comes from ITU-T Recommendation X.509 [2], and RFC 5280 profiles it for the internet [1]. TLS requires X.509 version 3 for the certificates both sides send, unless the two ends negotiate another type (RFC 8446 §4.4.2.2, §4.4.2.3) [3]. So an SSL/TLS certificate is an X.509 certificate: "X.509" names the format, "SSL certificate" names the use. This SSL and TLS glossary entry covers the fields, the extensions TLS reads and Go's x509: errors.

Current version
version 3, stored as the value 2 [1]
Encoding
ASN.1, signed as DER [1]; files hold DER or PEM text
Structure
to-be-signed data, the signature algorithm, the signature value [1]
Read with
openssl x509 -in cert.pem -noout -text [7]

What an X.509 certificate contains

An X.509 certificate is one ASN.1 sequence of three parts: the to-be-signed certificate (tbsCertificate), the algorithm the issuer signed it with, and the signature value [1]. openssl asn1parse decodes the DER of this page's test certificate and shows them:

$ openssl asn1parse -in cert.pem -i
    0:d=0  hl=4 l= 827 cons: SEQUENCE
    4:d=1  hl=4 l= 736 cons:  SEQUENCE
  744:d=1  hl=2 l=  10 cons:  SEQUENCE
  756:d=1  hl=2 l=  73 prim:  BIT STRING

The 736-byte sequence is the to-be-signed part, with these fields [1]:

Fields of the to-be-signed certificate
FieldWhat it holds
Version3 (value 2) whenever extensions are present, §4.1.2.1
Serial numbera positive integer, unique among the certificates one CA issues, §4.1.2.2
Signaturethe signature algorithm; must match the outer one, §4.1.1.2
Issuerthe name of the authority that signed it, §4.1.2.4
ValiditynotBefore and notAfter: the dates between which it may be used (§6.1.3) and the CA keeps status information about it (§4.1.2.5)
Subjectthe name of the entity that holds the public key, §4.1.2.6
Subject public key infothe public key and its algorithm, such as RSA 2048 or ECDSA P-256
Extensionsnames and usage rules, version 3 only, §4.2

Versions 1, 2 and 3

X.509 version 3 extends version 2 with extensions. A certificate with only the basic fields should be version 1, and CAs that follow RFC 5280 must not use the unique identifiers versions 2 and 3 allow [1]. Signing the test request without extensions, OpenSSL 3.0.13 wrote Version: 1 (0x0).

The extensions that matter for TLS

For names and usage, a TLS client reads the extensions listed below. Each extension in an X.509 version 3 certificate is marked critical or non-critical, and RFC 5280 sets the rule: a system that meets a critical extension it does not recognize must reject the certificate, and an unknown non-critical one may be ignored [1].

  • Subject Alternative Name. The host names the certificate covers. Under RFC 9525, a server's identity can only be expressed in this extension, and the subject's common name is not used [4]. See Subject Alternative Names.

  • Basic Constraints. Whether the certified public key may verify signatures on other certificates. A website certificate has CA:FALSE; a CA certificate whose key signs certificates has CA:TRUE, with the extension marked critical [1].

  • Key Usage and Extended Key Usage. What the key may do. A website certificate carries TLS Web Server Authentication, the serverAuth purpose; a client certificate for mutual TLS carries TLS Web Client Authentication [1].

Issuer, revocation and log extensions

The other X.509 extensions point a client to the issuing certificate authority, its revocation list and public logs:

  • Authority Information Access. Where to download the issuer's certificate, as a single certificate in DER or a certs-only CMS bundle, and, if offered, the OCSP responder's address (RFC 5280 §4.2.2.1) [1].

  • CRL Distribution Points. Where the issuer publishes its revocation list. CRLs list revoked certificates by serial number [1]. See revocation.

  • Subject and Authority Key Identifiers. Identify this certificate's key and the key that signed it, to make building the certification path easier [1].

  • Signed Certificate Timestamps. A log's signed promise to add the certificate to its public record, stored under OID 1.3.6.1.4.1.11129.2.4.2 (RFC 6962 §3, §3.3) [5]; see Certificate Transparency.

Critical and non-critical: a test

The test leaf was signed twice with an unknown extension under a private OID, once critical and once not. Here is what OpenSSL 3.0.13 and Go 1.27.2 did with each certificate:

How OpenSSL and Go treat an unknown critical extension
Unknown extensionopenssl verifyGo crypto/x509
marked criticalerror 34 … unhandled critical extensionx509: unhandled critical extension
not criticalOKverified

How to read an X.509 certificate

openssl x509 -text prints every field [7]. Shortened output for the test certificate:

$ openssl x509 -in cert.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Example Test Intermediate
        Validity
            ...
        Subject: CN = example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com
            ...
    Signature Algorithm: ecdsa-with-SHA256

The two algorithms belong to different keys. rsaEncryption is the subject's own key. ecdsa-with-SHA256 is how the intermediate signed, and it appears twice because RFC 5280 requires the copy inside the signed data to match the one outside [1]. Printing single fields, reading a live server with openssl s_client and checking expiry are on OpenSSL commands.

Why one changed byte breaks the certificate

The issuer signs the DER encoding of the whole to-be-signed part [1], so editing any field invalidates the signature. In the test, one letter of www.example.com in the DER file was changed, and this is what OpenSSL then read and said:

$ openssl x509 -inform der -in tampered.der -noout -ext subjectAltName
X509v3 Subject Alternative Name:
    DNS:example.com, DNS:www.xxample.com
$ openssl verify -CAfile root.pem -untrusted int.pem tampered.der
error 7 at 0 depth lookup: certificate signature failure

This is why an expiring certificate cannot be extended and has to be replaced; see renewal. Certificate pins on a public key hash the DER of the subject public key info (RFC 7469 §2.4) [6], so a new certificate for the same key keeps the pin valid.

File formats: PEM, DER and others

X.509 defines the content, not the file. A certificate is saved as DER, the binary encoding, or as PEM, the DER bytes in base64 between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- lines; PEM's labels and line rules have their own glossary entry. File extensions such as .crt, .cer and .pem do not reliably tell you which encoding a file uses. PFX (PKCS#12) and P7B (PKCS#7) bundle X.509 certificates, PFX together with the private key. Telling them apart and converting is on certificate formats.

Where X.509 certificates are used

The key purposes RFC 5280 defines for Extended Key Usage name the jobs: TLS server authentication, TLS client authentication, code signing, email protection, time stamping and OCSP signing [1].

  • HTTPS and TLS. The server sends its X.509 certificate during the TLS handshake [3], and the client checks the chain, dates and names.

  • Client authentication. In mutual TLS the client sends a certificate too, under the same X.509v3 rule [3].

  • Email. S/MIME agents process X.509 certificates and validate them as RFC 5280 describes (RFC 8550) [9].

  • VPNs. IKEv2 carries DER-encoded X.509 certificates in its Certificate payload (RFC 7296 §3.6) [9].

The format is the same in each case; the extensions and the trust store that checks them differ. Path validation starts from a trust anchor, such as the top CA of a hierarchy [1]; on the web those are root certificates. SSH is the exception. Servers are identified by host keys (RFC 4251 §4.1), and OpenSSH certificates are, in its manual's words, "a different, and much simpler, format to the X.509 certificates" [10]; see SSL vs SSH.

X.509 errors in Go programs

Messages that begin with x509: come from Go's crypto/x509 package; when TLS fails, Go's crypto/tls puts tls: failed to verify certificate: in front of them [8]. Docker Engine, Kubernetes and Terraform are written in Go [11]; when they verify a certificate with Go's standard library, these are the texts they print. Each row was reproduced with Go 1.27.2 on the test chain:

Go x509 error messages and the test cases that produced them
MessageWhat failedTest case
x509: certificate signed by unknown authorityno path to a trusted root; causes and fixes as for unable to get local issuer certificateintermediate not supplied; root not in the pool
x509: certificate has expired or is not yet valid: …the date check; the browser equivalent is ERR_CERT_DATE_INVALIDclock set after notAfter
x509: certificate is valid for example.com, www.example.com, not b.example.comthe requested name is not in the Subject Alternative Name listhost b.example.com
x509: certificate relies on legacy Common Name field, use SANs insteadthe name is only in the subject's common name, with no SAN extensionleaf without SAN
x509: unhandled critical extensiona critical extension Go does not knowprivate OID marked critical

FAQ

What is an X.509 certificate?

A data structure in the X.509 format that binds a public key to a name, such as a domain name, signed by a certificate authority. SSL/TLS certificates are X.509 certificates.

Is an SSL certificate an X.509 certificate?

Yes. TLS requires X.509 version 3 unless both sides negotiate another type. "SSL certificate" describes the use; X.509 describes the structure. [3]

What is the difference between X.509 and PEM?

X.509 is the certificate's structure. PEM is one way to store it in a file: the DER encoding in base64 text between BEGIN and END lines.

What does "x509: certificate signed by unknown authority" mean?

A Go program could not link the server's certificate to a root it trusts. In the test above, it appeared both when the intermediate was missing and when the root was not trusted.

What is the latest version of X.509?

Version 3, the newest of the three RFC 5280 defines; the version field holds 2. It added extensions, including Subject Alternative Name, which TLS relies on. [1]

Sources

  1. RFC 5280, X.509 certificate and CRL profile: §3.1, §4.1, §4.2, §5.1.2.6, §6.

  2. ITU-T Recommendation X.509, Public-key and attribute certificate frameworks.

  3. RFC 8446, TLS 1.3: §4.4.2, §4.4.2.2, §4.4.2.3.

  4. RFC 9525, Service Identity in TLS: §2, Appendix A.

  5. RFC 6962, Certificate Transparency: §3, §3.3.

  6. RFC 7469, Public Key Pinning: §2.4.

  7. OpenSSL 3.0 manual: openssl-x509, option -text; openssl-asn1parse; X509_STORE_CTX_get_error (errors 7 and 34).

  8. Go 1.27.2 source, crypto/x509/verify.go; crypto/x509/x509.go; crypto/tls/common.go.

  9. RFC 8550, S/MIME 4.0 Certificate Handling: Abstract; RFC 7296, IKEv2: §3.6.

  10. RFC 4251, SSH architecture: §4.1; ssh-keygen(1) manual, Certificates.

  11. go.mod of moby/moby, kubernetes/kubernetes, hashicorp/terraform.