Hands-on practice with OpenSSL: creating RSA and EC key pairs with genpkey, generating CSRs with req, issuing self-signed certificates with x509, extracting public keys, and learning about the default and legacy providers.

In episode 2 you understood the PKI architecture: certificates, CSRs, the chain of trust, and the CA hierarchy. Now it is time to get your hands dirty — we will use OpenSSL to create your own keys, CSRs, and certificates. All the practice in this episode is the foundation for building a private CA in episode 4.
This episode's roadmap: getting to know OpenSSL versions and the provider concept, creating RSA and EC key pairs, generating a CSR, issuing a self-signed certificate, extracting public keys, and checking fingerprints. By the end of this episode you will be comfortable using three core commands: openssl genpkey, openssl req, and openssl x509.
In April 2026, OpenSSL 4.0 was released as the latest version with various API updates and safer defaults. For those who prioritize production stability, the 3.5 LTS branch is the most widely recommended choice because it receives long-term support. Both use the same syntax for our needs in this series.
openssl version -aThe command above shows the version number and build details. Notice the OPENSSLDIR line; this directory contains the default configuration and CA certificates used by the system.
OpenSSL 3.x and above introduced the provider concept: modules that provide cryptographic algorithms. The default provider provides modern algorithms such as RSA, EC, AES, and SHA. The legacy provider is needed for old algorithms such as MD2 or some rarely used DES modes.
For our needs, the default provider is sufficient. Avoid using legacy algorithms unless truly necessary, because they are generally weaker and riskier. You can see the list of available commands with openssl list -commands.
Key pairs are created with genpkey. For RSA, you specify the key length; 2048 bits is the standard minimum, and 4096 bits for higher needs. For EC, you specify the curve used, for example prime256v1 (P-256) or secp384r1 (P-384):
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 \
-out root-ca/private/ca.key.pem
chmod 600 root-ca/private/ca.key.pemA common mistake: writing a private key with mode 0644 so every user can read it. Private keys must always be protected with permission 0600, meaning only the owner can read and write them. chmod 600 is a habit that must stick with you throughout this series.
Once the key pair is ready, the next step is creating a CSR with openssl req. A CSR contains the public key and the identity we want, signed with the private key:
openssl req -new -key root-ca/private/ca.key.pem \
-subj "/CN=server.lab.example.test" \
-addext "subjectAltName=DNS:server.lab.example.test,DNS:lab.example.test" \
-out leaf/server.csr.pemNotice the -addext that injects the SAN directly when creating the CSR. The SAN is very important because modern browsers reject certificates without a matching SAN. Check the CSR contents before sending it to the CA:
openssl req -in leaf/server.csr.pem -noout -textThe output shows the subject, public key, and the requested extensions. If there is an error at this stage, recreate the CSR; do not sign a CSR whose identity is wrong.
A self-signed certificate is signed by its own private key. It is suitable for local testing, but not for public identity. Create one with openssl x509 in request mode:
openssl x509 -req -in leaf/server.csr.pem \
-signkey root-ca/private/ca.key.pem \
-days 365 \
-copy_extensions copy \
-out leaf/server.cert.pemThe -copy_extensions copy option copies the SAN extensions from the CSR into the final certificate, so the result has the same SAN. Without this option, the certificate is issued without a SAN and will be rejected by browsers. To inspect the result, openssl x509 -in leaf/server.cert.pem -noout -text shows all details including the SAN and signature.
Two inspection operations are frequently used: extracting the public key from a private key, and computing the certificate fingerprint for quick identification:
openssl pkey -in root-ca/private/ca.key.pem -pubout -out ca.pub.pem
openssl x509 -in leaf/server.cert.pem -noout -fingerprint -sha256The extracted public key can be shared without risk. A fingerprint is a short, unique hash value for a certificate; you can compare it between copies to confirm two files are actually the same certificate.
Besides checking certificates, you also need to inspect the private key and make sure the CSR matches the key used:
openssl pkey -in root-ca/private/ca.key.pem -noout -textThe output shows the algorithm, key length, and curve parameters. Check that the values match expectations; for example, an EC key must show the P-256 or P-384 curve.
To make sure the public key inside the CSR matches the private key you own, extract both and compare:
openssl pkey -in root-ca/private/ca.key.pem -pubout -out pub-from-key.pem
openssl req -in leaf/server.csr.pem -pubkey -noout -out pub-from-csr.pem
diff pub-from-key.pem pub-from-csr.pemIf diff produces no output, both public keys are identical and the CSR was created from the correct key. If they differ, the CSR was signed by another key; do not continue before fixing the key and CSR pair.
In episode 3 you practiced the core of OpenSSL: creating RSA and EC key pairs with genpkey, generating CSRs with req, issuing self-signed certificates with x509, and extracting public keys and fingerprints. All of these commands will be used repeatedly when building a private CA.
Key takeaways:
In the next episode, episode 4, we will build a two-tier private CA — an offline Root CA and an online Intermediate CA — complete with openssl.cnf configuration and the correct CSR signing flow. Get your lab folder ready!