Home / Alt manpages / x509v3_config(5ssl)

  • x509v3_config(5ssl)
  • OpenSSL config
  • linux

Set X.509v3 Extensions with an OpenSSL Config File

A certificate comes back missing its subjectAltName, and that gap almost always traces to the x509v3_config extension sections. Every modern browser rejects a certificate like that. This guide builds a small config file, uses it to issue a test certificate, and inspects the resulting extensions. The same pattern works for a certificate signing request (CSR) and for a CA signing operation.

  • Time: about 15 minutes.
  • You need: OpenSSL 3.x, a shell, and permission to write temporary files. This guide uses OpenSSL 3.6.4 as installed here.

The private key and certificate in the examples are test material only; do not use them for a real service.

1. Decide what the certificate is for

Write down the certificate's role before writing its configuration.

  • End-entity TLS certificate: normally CA:false, a key usage suitable for its key, an extended key usage such as serverAuth, and every DNS name or IP address that clients will use in subjectAltName.
  • CA certificate: must have CA:true.

These are certificate constraints, not comments for a human operator. Do not put a real private key in a shared configuration file, and do not assume a certificate's common name replaces a subject alternative name: modern TLS clients check the SAN extension for the identity.

2. Create the extension sections

Save this as /tmp/x509v3-guide.cnf. The req section tells openssl req where the distinguished name and extension sections are. x509_extensions applies when -x509 creates a certificate. req_extensions applies when the command creates a CSR.

[ req ]
distinguished_name = dn
prompt = no
x509_extensions = extensions
req_extensions = extensions

[ dn ]
CN = example.test

[ extensions ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
subjectKeyIdentifier = hash

[ alt_names ]
DNS.1 = example.test
IP.1 = 192.0.2.10

Each extension entry has the shape name = [critical, ]value(s). A multi-valued extension can use comma-separated values, or point at another section with @section_name. The latter is easier to review and is required when a value itself contains a comma.

For example, subjectAltName = @alt_names keeps the names separate from the extension list. The numeric suffixes matter: OpenSSL does not retain two identical field names in one section, so use DNS.1, DNS.2 and so on when there are several names.

3. Issue a disposable certificate

This command generates a new RSA key and a self-signed certificate. It changes state by creating two files, so use a temporary directory or replace the paths with controlled locations. No elevated privileges are needed.

openssl req -new -x509 -nodes -newkey rsa:2048 \
  -keyout /tmp/x509v3-guide.key \
  -out /tmp/x509v3-guide.crt \
  -days 1 \
  -config /tmp/x509v3-guide.cnf

Expected result: OpenSSL prints key-generation progress and exits with status 0. The certificate is valid for one day. The -nodes option leaves the generated private key unencrypted, which is convenient for a disposable test and unsafe for a key that must be retained.

Checkpoint

Confirm that the certificate contains the intended extensions.

openssl x509 -in /tmp/x509v3-guide.crt -noout -text \
  | sed -n '/X509v3 extensions:/,/Signature Algorithm/p'

You should see critical Basic Constraints with CA:FALSE, critical Key Usage containing Digital Signature and Key Encipherment, TLS Web Server Authentication, and SAN entries for example.test and 192.0.2.10. The subject key identifier should be a generated hash.

4. Use the same sections for a CSR

Remove the -x509 option and write a CSR instead. Because the example includes req_extensions = extensions, the requested extensions are carried in the CSR.

openssl req -new -nodes -newkey rsa:2048 \
  -keyout /tmp/x509v3-guide-req.key \
  -out /tmp/x509v3-guide.csr \
  -config /tmp/x509v3-guide.cnf

openssl req -in /tmp/x509v3-guide.csr -noout -text \
  | sed -n '/Requested Extensions:/,/Signature Algorithm/p'

A CSR expresses a request. The CA or signing command still decides which extensions enter the final certificate. In particular, do not assume that requested extensions are copied automatically when using openssl req -x509 or a CA workflow; select the extension section explicitly and check the issued certificate.

5. Choose the right extension form

For a small value, the short form is clear:

basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
subjectAltName = DNS:ca.example.test

pathlen:0 permits the CA to sign end-entity certificates but not subordinate CAs. It is a limit on the chain below this CA, not a request to create a zero-length certificate.

Use a referenced section for more involved data. This avoids the comma separator being mistaken for part of a URI or directory name:

[ extensions ]
subjectAltName = @names

[ names ]
subjectAltName = URI:ldap://somehost.example/CN=foo,OU=bar

The same numbered-field rule applies to email addresses, DNS names and other repeated values. If an extension is unsupported, the manpage describes an arbitrary extension syntax, but that is a security-sensitive escape hatch: use a documented OID and verify the encoded result rather than guessing.

Common traps and recovery

  • Duplicate names silently override. A later entry with the same extension name overrides an earlier one. Keep one authoritative entry for each extension.
  • Two email lines are not two values. Putting email = [email protected] and email = [email protected] in one section does not create two values; number them.
  • critical changes processing behaviour. Add it only when relying parties are expected to understand and enforce that extension.
  • Do not hand-write the key identifier. subjectKeyIdentifier = hash asks OpenSSL to derive it; supplying a literal hexadecimal identifier is discouraged by the manpage.
  • Exit status is not proof. Do not confuse a successful OpenSSL exit status with a correct certificate. Inspect the final certificate, and test it with the client software that will consume it.

To undo this tutorial's temporary state, remove only the files it created:

rm -f /tmp/x509v3-guide.cnf \
  /tmp/x509v3-guide.key /tmp/x509v3-guide.crt \
  /tmp/x509v3-guide-req.key /tmp/x509v3-guide.csr

Warning

Do not run that cleanup with paths changed to a directory containing real keys or certificates. If you used different paths, verify each target with ls -l before removing anything.

Done means

  • Sections separated. The configuration has separate distinguished-name, extension and repeated-name sections.
  • Extensions correct. The certificate has the intended CA constraint, key usages and SAN values.
  • Right hook used. You know whether your command needs x509_extensions or req_extensions.
  • Output verified. You inspected the emitted certificate rather than trusting the configuration file alone.