Home / Alt manpages / openssl-cmds(1ssl)

  • openssl-cmds(1ssl)
  • OpenSSL command
  • linux

Build and Check a Test Certificate with OpenSSL 3

You will generate a P-256 private key, create a certificate signing request (CSR), make a short-lived self-signed certificate for local testing, and check its subject alternative name (SAN). The commands use OpenSSL 3.6.1, installed here on Linux.

Allow about fifteen minutes. You need a shell and OpenSSL. The workflow is read-only apart from the files it creates in your chosen working directory, and none of the commands needs sudo. Do not use the self-signed certificate for a public service or treat it as a replacement for a certificate issued by your organisation's CA.

1. Check the installed OpenSSL

Start by checking the executable and library version you are about to use:

$ command -v openssl
/usr/bin/openssl
$ openssl version -v
OpenSSL 3.6.1 27 Jan 2026

Your path and version may differ. The option names below come from the installed OpenSSL 3 command set. OpenSSL commands generally write normal output to standard output, so use -out when a result must become a file rather than being mixed into your terminal output.

Checkpoint

Continue only if openssl version -v succeeds. If the command is missing, install the package using your distribution's normal package-management process, then rerun this check. Package installation may require elevated privileges, but the certificate workflow itself does not.

2. Create a working directory

Keep the test key, request and certificate together in a directory that is not used by a live service:

mkdir -p "$HOME/openssl-test"
cd "$HOME/openssl-test"
umask 077

The umask limits permissions on newly created files for this shell. It does not repair permissions on files that already exist. The private key is sensitive, even though this example is for testing.

If you need to abandon the test, stop here and remove this dedicated directory using your normal file-management process. Check the path carefully before any deletion. Do not point a clean-up command at a shared certificate directory.

3. Generate a P-256 private key

Use genpkey for a new EC key. The installed manual documents -algorithm EC and the ec_paramgen_curve:P-256 option:

$ openssl genpkey \
    -algorithm EC \
    -pkeyopt ec_paramgen_curve:P-256 \
    -out site.key
.....

The dots are generation status output and may vary. The default output format is PEM. The command writes an unencrypted private key, because this makes the small local test easy to repeat. That is a deliberate boundary: for a real key, decide how it will be stored, backed up and protected before generating it.

Check that the file exists without printing the key:

$ stat -c '%n %a bytes=%s' site.key
site.key 600 bytes=241

The exact size changes with OpenSSL versions and metadata. Do not paste the contents of site.key into a ticket, shell transcript or chat.

4. Create a CSR with a SAN

A CSR contains the public key, subject information and a request for extensions. For a hostname, put the name in subjectAltName; modern clients check SAN rather than relying on the common name alone:

$ openssl req -new \
    -key site.key \
    -subj '/CN=service.example.test' \
    -addext 'subjectAltName=DNS:service.example.test' \
    -out site.csr

This non-interactive form is useful for a repeatable test. Replace service.example.test with the exact DNS name your test client will use. Do not put a real production hostname in a test certificate unless you have a clear reason and a plan to prevent confusion.

Verify the CSR's own signature and inspect its subject:

$ openssl req -in site.csr -noout -verify -subject
Certificate request self-signature verify OK
subject=CN=service.example.test

This proves that the request is internally signed by the private key associated with its public key. It does not prove that a CA trusts the request, that the hostname resolves, or that a future certificate will contain the requested extension.

5. Make a short-lived self-signed certificate

For a local TLS listener or an isolated integration test, make a certificate valid for seven days:

$ openssl req -x509 -new \
    -key site.key \
    -subj '/CN=service.example.test' \
    -addext 'subjectAltName=DNS:service.example.test' \
    -days 7 \
    -out site.crt

req -x509 creates a certificate directly instead of a CSR. It is self-signed, so a client that does not explicitly trust site.crt should reject it. That rejection is expected and is one reason this is a test artefact, not a deployment recipe.

Inspect the result:

$ openssl x509 -in site.crt -noout \
    -subject -issuer -dates -ext subjectAltName
subject=CN=service.example.test
issuer=CN=service.example.test
notBefore=Sep 25 07:22:45 2026 GMT
notAfter=Oct  2 07:22:45 2026 GMT
X509v3 Subject Alternative Name:
    DNS:service.example.test

The timestamps will be different. Matching subject and issuer show that this certificate is self-signed. The SAN line is the useful hostname check; a certificate with only a common name is not an equivalent test.

6. Verify the hostname and trust explicitly

Check that the certificate matches the hostname your client is expected to use:

$ openssl x509 -in site.crt -noout \
    -checkhost service.example.test
Hostname service.example.test does match certificate

Now ask OpenSSL to verify the certificate while explicitly treating this same file as a trust anchor:

$ openssl verify -CAfile site.crt site.crt
site.crt: OK

That command is a narrow, intentional test. It says that this self-signed certificate is trusted because you supplied it as a CA file. It does not add the certificate to the operating system trust store and does not make browsers or unrelated services trust it. If you later configure a test client, pass the certificate through that client's documented test-trust option rather than changing the host-wide CA store.

To check expiry without parsing dates, give checkend a number of seconds:

$ openssl x509 -in site.crt -noout -checkend 518400
Certificate will not expire

A zero exit status means the certificate will remain valid for the requested period. A non-zero status means it expires sooner, or the check failed. Record the status immediately if a script consumes it.

7. Keep adjacent tools in their lanes

OpenSSL groups many commands under one application, but they answer different questions. Use req for CSRs, x509 for certificate inspection, and verify for chain validation. Use dgst -sha256 FILE when you need a digest of a file, not as a substitute for certificate verification.

For a password-protected data file, enc can perform a reversible local round trip. Prefer a password source that is not exposed in shell history, and use PBKDF2 explicitly:

$ openssl enc -aes-256-cbc -pbkdf2 -salt \
    -pass file:./passphrase.txt \
    -in plain.txt -out plain.txt.enc
$ openssl enc -d -aes-256-cbc -pbkdf2 \
    -pass file:./passphrase.txt \
    -in plain.txt.enc -out plain.txt.restored
$ cmp plain.txt plain.txt.restored

This example changes files and the passphrase file is itself sensitive. Do not use -nosalt except for a compatibility or test case, and do not treat successful encryption as backup. A lost passphrase cannot be recovered by OpenSSL.

Done means

  • openssl version -v reported the installed version you intended to use.
  • site.key is protected and has not been copied into logs or tickets.
  • site.csr passed its self-signature check.
  • site.crt contains the expected SAN and has a deliberately short lifetime.
  • -checkhost matched the test hostname.
  • verify -CAfile site.crt site.crt passed only because trust was supplied explicitly.
  • You know which test files to remove or retain, and have not changed a system trust store or live service.