Skip to content

Instantly share code, notes, and snippets.

@qrkourier
Created September 26, 2025 19:27
Show Gist options
  • Save qrkourier/872b3d29113e8f51cddda4a89728c80f to your computer and use it in GitHub Desktop.
Save qrkourier/872b3d29113e8f51cddda4a89728c80f to your computer and use it in GitHub Desktop.
generate ca, client, and server certs for testing
#!/bin/bash
#
# Generates a self-signed user/client certificate for authentication purposes.
# It creates a private key, a public key, the certificate, and a PKCS#12
# bundle for easy import into browsers or for use with tools like curl.
set -e
# --- Configuration ---
# Modern, preferred elliptic curve for the private key.
# secp384r1 offers an excellent balance of security and performance.
CURVE_NAME="secp384r1"
# Validity of the certificate in days. 10 years is common for client certs.
VALIDITY_DAYS=3650
# --- User Input ---
echo "--- Client Certificate Generator ---"
read -p "Enter the user's email address (e.g., [email protected]): " EMAIL
read -p "Enter a base filename for the output files (e.g., 'john_doe_auth') [default: cert]: " FILENAME
FILENAME=${FILENAME:-cert}
# Prompt for the PKCS#12 export password securely
echo "You will now create a password for the PKCS#12 file (.p12)."
echo "This password is required when importing the file into a browser or keychain."
read -s -p "Enter Export Password: " P12_PASSWORD
echo
read -s -p "Verify Export Password: " P12_PASSWORD_VERIFY
echo
if [ "$P12_PASSWORD" != "$P12_PASSWORD_VERIFY" ]; then
echo "Error: Passwords do not match."
exit 1
fi
echo
echo "--- Starting Generation ---"
# --- Step 1: Generate the Certificate Authority (CA) ---
echo "1. Generating CA private key (${FILENAME}_ca.key)..."
openssl ecparam -name "$CURVE_NAME" -genkey -out "${FILENAME}_ca.key"
echo " CA private key generated."
echo "2. Creating CA certificate (${FILENAME}_ca.crt)..."
read -p "Enter the CA organization name (e.g., 'My Test CA') [default: Test CA]: " CA_ORG
CA_ORG=${CA_ORG:-Test CA}
openssl req \
-new \
-x509 \
-key "${FILENAME}_ca.key" \
-out "${FILENAME}_ca.crt" \
-days "$VALIDITY_DAYS" \
-subj "/CN=${CA_ORG}/O=${CA_ORG}" \
--addext "keyUsage = critical, keyCertSign, cRLSign" \
--addext "basicConstraints = critical, CA:true" \
--addext "subjectKeyIdentifier = hash"
echo " CA certificate created."
# --- Step 3: Generate Client Private Key ---
echo "3. Generating client private key (${FILENAME}.key)..."
openssl ecparam -name "$CURVE_NAME" -genkey -out "${FILENAME}.key"
echo " Client private key generated."
# --- Step 4: Generate Client Certificate Signing Request ---
echo "4. Creating client certificate signing request..."
openssl req \
-new \
-key "${FILENAME}.key" \
-out "${FILENAME}.csr" \
-subj "/CN=${EMAIL}"
# --- Step 5: Sign Client Certificate with CA ---
echo "5. Signing client certificate with CA (${FILENAME}.crt)..."
openssl x509 \
-req \
-in "${FILENAME}.csr" \
-CA "${FILENAME}_ca.crt" \
-CAkey "${FILENAME}_ca.key" \
-CAcreateserial \
-out "${FILENAME}.crt" \
-days "$VALIDITY_DAYS" \
-extensions client_ext \
-extfile <(echo "[client_ext]
keyUsage = digitalSignature
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer")
echo " Client certificate signed."
# --- Step 6: Extract the Client Public Key ---
echo "6. Extracting client public key (${FILENAME}.pub)..."
openssl ec -in "${FILENAME}.key" -pubout -out "${FILENAME}.pub"
echo " Client public key extracted."
# --- Step 7: Create the Client PKCS#12 Keystore ---
echo "7. Creating client PKCS#12 keystore (${FILENAME}.p12)..."
# This bundles the private key and the certificate into a single, password-protected file.
# The -name attribute is a "friendly name" that appears in the browser's UI.
openssl pkcs12 \
-export \
-in "${FILENAME}.crt" \
-inkey "${FILENAME}.key" \
-out "${FILENAME}.p12" \
-name "${EMAIL}'s Authentication Key" \
-passout pass:"${P12_PASSWORD}"
echo " Keystore created."
echo
echo "--- Success! ---"
echo "Generated files in the current directory:"
ls -l "${FILENAME}".*
echo
echo "--- Next Steps ---"
echo "-> Import '${FILENAME}.p12' into your web browser or system keychain. You will be prompted for the password you created."
echo "-> For command-line use with curl:"
echo " curl --cert ${FILENAME}.crt --key ${FILENAME}.key https://your-secure-service.com"
echo " OR"
echo " curl --cert-type P12 --cert ${FILENAME}.p12:YourPassword https://your-secure-service.com"
echo
echo "IMPORTANT: Guard the private key file ('${FILENAME}.key') and the PKCS#12 file ('${FILENAME}.p12') carefully. Anyone with access to them can impersonate you."
echo
echo "--- Generating Server Certificate ---"
# --- Step 8: Generate Server Private Key ---
echo "8. Generating server private key (${FILENAME}_server.key)..."
openssl ecparam -name "$CURVE_NAME" -genkey -out "${FILENAME}_server.key"
echo " Server private key generated."
# --- Step 9: Generate Server Certificate Signing Request ---
echo "9. Creating server certificate signing request..."
read -p "Enter the server hostname/FQDN (e.g., server.example.com): " SERVER_HOSTNAME
SERVER_HOSTNAME=${SERVER_HOSTNAME:-localhost}
openssl req \
-new \
-key "${FILENAME}_server.key" \
-out "${FILENAME}_server.csr" \
-subj "/CN=${SERVER_HOSTNAME}"
# --- Step 10: Sign Server Certificate with CA ---
echo "10. Signing server certificate with CA (${FILENAME}_server.crt)..."
openssl x509 \
-req \
-in "${FILENAME}_server.csr" \
-CA "${FILENAME}_ca.crt" \
-CAkey "${FILENAME}_ca.key" \
-CAcreateserial \
-out "${FILENAME}_server.crt" \
-days "$VALIDITY_DAYS" \
-extensions server_ext \
-extfile <(echo "[server_ext]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = DNS:${SERVER_HOSTNAME},DNS:localhost,IP:127.0.0.1
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer")
echo " Server certificate signed."
# --- Step 11: Extract Server Public Key ---
echo "11. Extracting server public key (${FILENAME}_server.pub)..."
openssl ec -in "${FILENAME}_server.key" -pubout -out "${FILENAME}_server.pub"
echo " Server public key extracted."
# --- Step 12: Create Server PKCS#12 Keystore ---
echo "12. Creating server PKCS#12 keystore (${FILENAME}_server.p12)..."
openssl pkcs12 \
-export \
-in "${FILENAME}_server.crt" \
-inkey "${FILENAME}_server.key" \
-out "${FILENAME}_server.p12" \
-name "${SERVER_HOSTNAME} Server Key" \
-passout pass:"${P12_PASSWORD}"
echo " Server keystore created."
# Clean up temporary files
rm -f "${FILENAME}.csr" "${FILENAME}_server.csr"
echo
echo "--- Complete Success! ---"
echo "Generated CERTIFICATE AUTHORITY files:"
ls -l "${FILENAME}"_ca.*
echo
echo "Generated CLIENT certificate files:"
ls -l "${FILENAME}".key "${FILENAME}".crt "${FILENAME}".pub "${FILENAME}".p12
echo
echo "Generated SERVER certificate files:"
ls -l "${FILENAME}"_server.*
echo
echo "--- Usage Instructions ---"
echo "CERTIFICATE AUTHORITY:"
echo "-> Install '${FILENAME}_ca.crt' as a trusted root CA in browsers/systems to trust your certificates"
echo "-> Keep '${FILENAME}_ca.key' extremely secure - it can sign new certificates"
echo
echo "CLIENT CERTIFICATE:"
echo "-> Import '${FILENAME}.p12' into your web browser or system keychain for client authentication."
echo "-> For command-line client use with curl:"
echo " curl --cert ${FILENAME}.crt --key ${FILENAME}.key --cacert ${FILENAME}_ca.crt https://your-secure-service.com"
echo
echo "SERVER CERTIFICATE:"
echo "-> Use '${FILENAME}_server.crt' and '${FILENAME}_server.key' to configure your web server (Apache, Nginx, etc.)"
echo "-> For testing with openssl s_server:"
echo " openssl s_server -cert ${FILENAME}_server.crt -key ${FILENAME}_server.key -CAfile ${FILENAME}_ca.crt -port 8443"
echo
echo "IMPORTANT: Guard ALL private key files carefully, especially the CA key. Anyone with access to them can impersonate you, your server, or create new certificates."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment