CA.pl turns the handful of OpenSSL subcommands you would otherwise chain by hand into one script for standing up a disposable certificate authority. You will build the CA, generate a request, sign it, verify the result and package it as a PKCS#12 file, all useful for a lab, a browser test or a development service, but none of it a recipe for a production public CA. Allow about 20 minutes, most of it answering prompts for names and passwords.
The examples use the CA.pl installed with the Ubuntu openssl package, version 3.0.13-0ubuntu3.15. On this machine the script lives at /usr/lib/ssl/misc/CA.pl, off the normal shell PATH. The wrapper follows whichever OpenSSL version the openssl command on your path reports, unless you set OPENSSL.
Security boundary: Keep this work in a disposable directory. If you import the CA certificate anywhere, its private key can sign certificates that clients will trust. Never reuse it for a real service, and never let it leave the test environment.
CA.pl writes fixed names, demoCA, newkey.pem, newreq.pem, into whatever directory you run it from. Use a fresh one so an old request or CA database cannot get mixed into the run:
$ workdir=$(mktemp -d /tmp/ca-pl-demo.XXXXXX)
$ cd "$workdir"
$ command -v openssl
/home/linuxbrew/.linuxbrew/bin/openssl
$ test ! -e demoCA && echo 'empty CA workspace'
empty CA workspace
The workdir variable only lasts for this shell. Prefer a named directory instead? Give it permissions that shut out other users and confirm it holds no leftover CA files first.
Run the script by its installed path. This is read-only and needs no sudo:
$ /usr/lib/ssl/misc/CA.pl -help
Usage:
CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter]
CA.pl -pkcs12 [certname]
CA.pl -verify certfile ...
CA.pl -revoke certfile [reason]
It is deliberately a thin front end over OpenSSL's req, ca, pkcs12, x509 and verify subcommands. Need a different policy, extension or file name? Use the relevant OpenSSL command directly rather than assuming CA.pl hides a switch for it.
Start the interactive setup:
$ /usr/lib/ssl/misc/CA.pl -newca
Press ENTER at the first prompt to create a new CA, answer the distinguished-name questions, then set a strong passphrase when OpenSSL asks for the CA private key. This creates demoCA/ in the current directory: demoCA/private/cakey.pem, demoCA/cacert.pem, a certificate database and the directories for issued certificates.
Checkpoint: Stop if the output says demoCA/index.txt or demoCA/serial already exists. CA.pl will not overwrite an existing hierarchy, and you should not delete one casually either: that database is the record of every certificate issued and revoked. If this really was a failed disposable attempt, leave it alone and start fresh in a new temporary directory.
$ test -s demoCA/cacert.pem && test -s demoCA/private/cakey.pem && echo 'CA created'
CA created
Create the user key and request:
$ /usr/lib/ssl/misc/CA.pl -newreq
OpenSSL asks for a passphrase to protect newkey.pem and for the request's subject fields. The key comes out encrypted; the request lands in newreq.pem. You can hand extra arguments to the underlying req command, for example to set a subject without giving up key encryption:
$ /usr/lib/ssl/misc/CA.pl -newreq -extra-req '-subj /C=GB/ST=Test/L=Test/O=Example/OU=Lab/CN=example.invalid'
Pick one, not both: the first form is fully interactive, the second still prompts for the encrypted key's passphrase but takes the subject from -subj. Check the files before moving on:
$ test -s newkey.pem && test -s newreq.pem && echo 'request and private key created'
request and private key created
$ openssl req -in newreq.pem -noout -subject
subject=...
Issue the certificate against the CA database:
$ /usr/lib/ssl/misc/CA.pl -sign
OpenSSL asks for the CA's private-key passphrase and shows you the request. Only confirm if the subject is the one you meant to sign. The signed certificate lands in newcert.pem, and the CA database records the issuance:
$ test -s newcert.pem && echo 'certificate created'
certificate created
$ openssl x509 -in newcert.pem -noout -subject -issuer
subject=...
issuer=...
The issuer field should name the CA you just created, not the request's own subject. A certificate file existing on disk proves nothing by itself, check that relationship before you import anything into a browser or service.
-verify checks a certificate against demoCA/cacert.pem. Name the issued certificate explicitly:
$ /usr/lib/ssl/misc/CA.pl -verify newcert.pem
newcert.pem: OK
Some OpenSSL builds print extra diagnostic lines, but a genuine pass ends with OK and a zero exit status. If verification fails, check you are still sitting in the directory that holds the matching demoCA hierarchy. Do not copy a CA certificate over from another test directory just to make the check pass.
Package the user certificate, its private key and the CA certificate together:
$ /usr/lib/ssl/misc/CA.pl -pkcs12 'Example Lab Certificate'
PKCS #12 file is in newcert.p12
$ test -s newcert.p12 && echo 'PKCS#12 bundle created'
PKCS#12 bundle created
CA.pl expects newcert.pem, newkey.pem and demoCA/cacert.pem at exactly these relative paths. It prompts for the encrypted key's passphrase and a fresh export passphrase. Treat newcert.p12 as sensitive, it holds the private key. The name you pass is just the friendly label shown in most browser import dialogs.
-newcert is not -newreq. It creates a self-signed certificate instead of a request for your CA, writing newkey.pem and newcert.pem directly. Skip it if you actually want to exercise the CA database.-newreq-nodes skips key encryption. It behaves like -newreq but leaves the private key unencrypted. Fine for a disposable test protected some other way, a poor default for a key you intend to keep.pwd and find . -maxdepth 2 -type f before rerunning a command.newcert.pem alone. For a full disposable reset, abandon the directory and start a fresh one under /tmp rather than deleting a hierarchy that might still be needed to validate existing certificates.demoCA/cacert.pem and its private key exist in a dedicated test directory.newreq.pem exists with an encrypted newkey.pem, unless you deliberately chose -newreq-nodes for a disposable test.newcert.pem was issued by the test CA and passed CA.pl -verify.newcert.p12 exists, has an export passphrase and is treated as a private-key container.