Skip to content

Instantly share code, notes, and snippets.

@gmassawe
Last active March 18, 2026 00:49
Show Gist options
  • Select an option

  • Save gmassawe/b29643dc98e9905303a43c5affa0e278 to your computer and use it in GitHub Desktop.

Select an option

Save gmassawe/b29643dc98e9905303a43c5affa0e278 to your computer and use it in GitHub Desktop.
Creating Self Signed Certificate

OpenSSL Cheat Sheet for Self-Signed Certificates

OpenSSL version note: Commands below target OpenSSL 3.x. Some flags differ in 1.x — noted inline where relevant.


Create Self-Signed Certificates with OpenSSL

Root CA

Create Root CA Key (With Strong Encryption)

Use -aes256 to protect the key with a passphrase:

openssl genpkey -algorithm RSA -out root.key -aes256 -pkeyopt rsa_keygen_bits:4096

Or with Ed25519 (modern, recommended where compatibility allows):

openssl genpkey -algorithm Ed25519 -aes256 -out root.key

Create Root CA Certificate

Generate a self-signed Root CA certificate, valid for 10 years:

openssl req -new -x509 -sha256 -days 3650 -key root.key -extensions v3_ca -out root.crt

Intermediate CA

Create Intermediate CA Key

openssl genpkey -algorithm RSA -out ca.key -aes256 -pkeyopt rsa_keygen_bits:4096

Create Intermediate CA Request

openssl req -new -key ca.key -out ca.csr

Sign Intermediate CA Request with Root CA

Use an extension file (v3_intermediate_ca.ext) for proper CA settings:

openssl x509 -req -in ca.csr -CA root.crt -CAkey root.key \
  -CAcreateserial -extfile v3_intermediate_ca.ext \
  -days 3650 -sha256 -out ca.crt

Create CA Chain File

Combine the Intermediate CA and Root CA certificates:

cat ca.crt root.crt > ca_chain.crt

Server Certificates

Create Server Certificate Key

openssl genpkey -algorithm RSA -out server.key -aes256 -pkeyopt rsa_keygen_bits:4096

Create Server Certificate Request

Ensure the request includes a Subject Alternative Name (SAN):

openssl req -new -key server.key -out server.csr -config openssl.cnf

Sign Server Certificate with Intermediate CA

Use an extension file (v3_server_cert.ext) for SAN and proper key usage:

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -extfile v3_server_cert.ext \
  -days 730 -sha256 -out server.crt

Public vs internal PKI: Publicly trusted certificates issued by commercial CAs are capped at 398 days (enforced by browsers since 2020). The 730-day limit here is fine for internal/private PKI only.

Generate Diffie-Hellman Parameters

For TLS 1.2 cipher suites that use DHE key exchange:

openssl dhparam -out dhparam.pem 4096

TLS 1.3 note: TLS 1.3 uses X25519 for key exchange by default and does not use custom DH parameters. dhparam is only relevant if you are still supporting TLS 1.2 DHE cipher suites.


Client Certificates

Create Client Certificate Key

openssl genpkey -algorithm RSA -out client.key -aes256 -pkeyopt rsa_keygen_bits:4096

Create Client Certificate Request

openssl req -new -key client.key -out client.csr -config openssl.cnf

Sign Client Certificate

Use a custom extension file (v3_client_cert.ext):

openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -extfile v3_client_cert.ext \
  -days 730 -sha256 -out client.crt

Convert Client Certificate to PKCS12 Format

openssl pkcs12 -export -certfile ca_chain.crt -in client.crt -inkey client.key -out client.p12

Verify Certificates

Verify Certificate Against CA

openssl verify -verbose -CAfile ca_chain.crt server.crt

Verify Certificate Matches Private Key

openssl x509 -noout -modulus -in server.crt | openssl sha256
openssl pkey -noout -modulus -in server.key | openssl sha256

Changed from MD5 — MD5 is a broken hash algorithm. Both commands must produce the same SHA-256 output for the key and certificate to match.

For Ed25519/EC keys, use the public key fingerprint instead (modulus doesn't apply):

openssl pkey -in server.key -pubout | openssl sha256
openssl x509 -in server.crt -pubkey -noout | openssl sha256

Check SSL Protocol Support

openssl s_client -connect HOST:443 -tls1_3
openssl s_client -connect HOST:443 -tls1_2

TLS 1.0 and TLS 1.1 are deprecated by RFC 8996. A server that only accepts those versions is a security finding.

Check SSL Cipher Support

openssl s_client -connect HOST:443 -cipher ${cipher}

Test SNI (Server Name Indication)

openssl s_client -connect HOST:443 -servername ${sni_host}

Test Client Certificate Authentication

openssl s_client -connect HOST:443 -cert client.crt -key client.key -state

Dropped -debug — it outputs raw bytes to the terminal and is rarely useful outside of deep protocol debugging.


Example Configuration Files

v3_intermediate_ca.ext

basicConstraints = CA:TRUE, pathlen:0
keyUsage = keyCertSign, cRLSign
authorityKeyIdentifier = keyid:always,issuer:always
subjectKeyIdentifier = hash

v3_server_cert.ext

basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com
DNS.2 = *.example.com

EC/Ed25519 key usage note: If using an EC or Ed25519 server key, replace keyEncipherment with keyAgreement in the keyUsage line — keyEncipherment is RSA-specific.

v3_client_cert.ext

basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = clientAuth

openssl.cnf

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
req_extensions = v3_req
default_md = sha256
prompt = no

[req_distinguished_name]
C = US
ST = New York
L = New York
O = Example Organization
OU = IT Department
CN = example.com

[v3_ca]
basicConstraints = CA:TRUE
keyUsage = keyCertSign, cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always

[v3_req]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com
DNS.2 = *.example.com

Recommendations

  1. Always use SHA-256 or higher for hashing. SHA-1 and MD5 are broken.
  2. Protect all private keys with strong passphrases using -aes256.
  3. Prefer modern key algorithms — Ed25519 for new systems, P-384 for ECDSA, RSA-4096 as a fallback for broad compatibility. Avoid RSA below 3072-bit for any new key.
  4. Always include SANs in server certificates. CN-only certificates are rejected by all modern clients.
  5. Target TLS 1.3 where possible. Disable TLS 1.0 and 1.1 — both are deprecated by RFC 8996.
  6. Keep OpenSSL updated to the latest stable 3.x release.
  7. Disable weak protocols and ciphers — SSLv2, SSLv3, RC4, DES, 3DES, MD5, and SHA-1 signatures have no place in current deployments.

For further details, refer to the OpenSSL Documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment