Skip to content

Instantly share code, notes, and snippets.

@sames
Last active February 28, 2025 14:17
Show Gist options
  • Save sames/accffde38c8eed5a6febb438a620f46c to your computer and use it in GitHub Desktop.
Save sames/accffde38c8eed5a6febb438a620f46c to your computer and use it in GitHub Desktop.
Helper Script to create a new Certificate Authority and Certificates for your local lan.
#!/bin/bash
# Certhelper - A tool for creating certificates with OpenSSL
#
# Usage:
# certhelper.sh -h | --help - Display this help
# certhelper.sh -ca [name] - Create a new Certificate Authority (default: rootca)
# certhelper.sh -cert <domain> [ca] - Create a new certificate for <domain> using specified CA
# certhelper.sh -i <ca-name|domain> - Install a certificate on the system (Linux only)
# certhelper.sh -list - List all existing CAs
# certhelper.sh -r <ca-name|domain> - Renew a certificate or CA
# certhelper.sh -nopw - Create keys without password protection
# certhelper.sh -rmpw <ca|domain> - Remove password from an existing key
# Default values for environment variables
DEFAULT_COUNTRY="DE"
DEFAULT_STATE="Nordrhein-Westfalen"
DEFAULT_LOCALITY="Leopoldshoehe"
DEFAULT_ORGANIZATION="Home Network"
DEFAULT_OU="IT Department"
DEFAULT_CA_CN="Local Root CA"
DEFAULT_CA_DAYS="3650" # 10 years
DEFAULT_CERT_DAYS="730" # 2 years
# Directories
CA_DIR="./ca"
CERTS_DIR="./certs"
# Flag for password protection
USE_PASSWORD=true
# Create the necessary directories
create_dirs() {
mkdir -p "$CA_DIR"
mkdir -p "$CERTS_DIR"
}
# Display help
show_help() {
echo "Certhelper - A tool for creating certificates with OpenSSL"
echo ""
echo "Usage:"
echo " $(basename "$0") -h | --help - Display this help"
echo " $(basename "$0") -ca [name] - Create a new Certificate Authority (default: rootca)"
echo " $(basename "$0") -cert <domain> [ca] - Create a new certificate for <domain> using specified CA"
echo " $(basename "$0") -i <ca-name|domain> - Install a certificate on the system (Linux only)"
echo " $(basename "$0") -list - List all existing CAs"
echo " $(basename "$0") -r <ca-name|domain> - Renew a certificate or CA"
echo " $(basename "$0") -nopw - Create keys without password protection"
echo " $(basename "$0") -rmpw <ca|domain> - Remove password from an existing key"
echo ""
echo "Environment variables:"
echo " CERT_COUNTRY - Country code (Default: $DEFAULT_COUNTRY)"
echo " CERT_STATE - State/Province (Default: $DEFAULT_STATE)"
echo " CERT_LOCALITY - City (Default: $DEFAULT_LOCALITY)"
echo " CERT_ORG - Organization (Default: $DEFAULT_ORGANIZATION)"
echo " CERT_OU - Organizational Unit (Default: $DEFAULT_OU)"
echo " CA_CN - Common Name for CA (Default: $DEFAULT_CA_CN)"
echo " CA_DAYS - CA certificate validity in days (Default: $DEFAULT_CA_DAYS)"
echo " CERT_DAYS - Domain certificate validity in days (Default: $DEFAULT_CERT_DAYS)"
echo ""
echo "Examples:"
echo " $(basename "$0") -ca mycompany"
echo " $(basename "$0") -cert nas.lan homelab"
echo " $(basename "$0") -i mycompany"
echo " $(basename "$0") -r nas.lan"
echo " $(basename "$0") -nopw -ca mycompany # Create CA without password protection"
echo ""
echo "Security Note:"
echo " By default, private keys are protected with a password. Use -nopw to disable password protection."
echo " Password-protected keys are more secure but may require manual intervention when used with services."
echo ""
echo "How to install the CA certificate on different platforms:"
echo ""
echo "Linux:"
echo " 1. Use the -i ca command which will install the CA into the system trust store:"
echo " $(basename "$0") -i ca"
echo " 2. Alternatively, manually copy the CA certificate to the system trust store:"
echo " sudo cp ca/ca.crt /usr/local/share/ca-certificates/local-ca.crt"
echo " sudo update-ca-certificates"
echo ""
echo "macOS:"
echo " 1. Open the ca.crt file with Keychain Access"
echo " 2. Add it to the System keychain"
echo " 3. Double-click the imported certificate"
echo " 4. Expand the 'Trust' section"
echo " 5. Change 'When using this certificate' to 'Always Trust'"
echo ""
echo "Windows:"
echo " 1. Double-click the ca.crt file"
echo " 2. Click 'Install Certificate'"
echo " 3. Select 'Local Machine' and click Next"
echo " 4. Select 'Place all certificates in the following store'"
echo " 5. Click 'Browse' and select 'Trusted Root Certification Authorities'"
echo " 6. Click 'Next' and then 'Finish'"
echo " 7. Alternatively, run this PowerShell command as Administrator:"
echo " Import-Certificate -FilePath ca\\ca.crt -CertStoreLocation Cert:\\LocalMachine\\Root"
}
# List all Certificate Authorities
list_cas() {
create_dirs
echo "Available Certificate Authorities:"
if [ -d "$CA_DIR" ]; then
local cas=$(find "$CA_DIR" -name "*.crt" | sed -e 's|.*/||' -e 's|\.crt$||')
if [ -z "$cas" ]; then
echo " No Certificate Authorities found."
else
for ca in $cas; do
local subject=$(openssl x509 -noout -subject -in "$CA_DIR/$ca.crt" 2>/dev/null | sed 's/subject= //')
echo " - $ca: $subject"
done
fi
else
echo " No Certificate Authorities found."
fi
}
# Create a Certificate Authority
create_ca() {
local ca_name="${1:-rootca}"
# Use environment variables or default values
local country="${CERT_COUNTRY:-$DEFAULT_COUNTRY}"
local state="${CERT_STATE:-$DEFAULT_STATE}"
local locality="${CERT_LOCALITY:-$DEFAULT_LOCALITY}"
local organization="${CERT_ORG:-$DEFAULT_ORGANIZATION}"
local ou="${CERT_OU:-$DEFAULT_OU}"
local cn="${CA_CN:-$DEFAULT_CA_CN}"
local days="${CA_DAYS:-$DEFAULT_CA_DAYS}"
create_dirs
# Check if CA already exists
if [ -f "$CA_DIR/$ca_name.key" ] || [ -f "$CA_DIR/$ca_name.crt" ]; then
echo "Warning: A Certificate Authority with name '$ca_name' already exists."
read -p "Do you want to overwrite it? (y/N): " confirm
if [[ "$confirm" != [yY] && "$confirm" != [yY][eE][sS] ]]; then
echo "Operation cancelled."
exit 0
fi
fi
echo "Creating Certificate Authority '$ca_name'..."
# Create the private key for the CA
if [ "$USE_PASSWORD" = true ]; then
echo "Creating password-protected CA private key..."
echo "You will be prompted to enter a password for the CA private key."
echo "This password will be required whenever you sign certificates with this CA."
openssl genrsa -des3 -out "$CA_DIR/$ca_name.key" 4096
else
echo "Creating CA private key without password protection..."
openssl genrsa -out "$CA_DIR/$ca_name.key" 4096
fi
# Create configuration file for CA
cat > "$CA_DIR/$ca_name.cnf" << EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
C = $country
ST = $state
L = $locality
O = $organization
OU = $ou
CN = $cn ($ca_name)
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
EOF
# Create the CA certificate
openssl req -x509 -new -nodes -key "$CA_DIR/$ca_name.key" -sha256 -days "$days" \
-out "$CA_DIR/$ca_name.crt" -config "$CA_DIR/$ca_name.cnf"
# Create serial number for future certificates
echo "01" > "$CA_DIR/$ca_name.srl"
echo "Certificate Authority '$ca_name' has been created:"
echo " - Private key: $CA_DIR/$ca_name.key"
echo " - Certificate: $CA_DIR/$ca_name.crt"
echo ""
echo "To install this CA certificate on your system, run:"
echo " $(basename "$0") -i $ca_name"
}
# Create a certificate
create_cert() {
if [ -z "$1" ]; then
echo "Error: Domain name is required"
echo "Usage: $(basename "$0") -cert <domain> [ca-name]"
exit 1
fi
local domain="$1"
local ca_name="${2:-rootca}"
# Check if the CA exists
if [ ! -f "$CA_DIR/$ca_name.key" ] || [ ! -f "$CA_DIR/$ca_name.crt" ]; then
echo "Error: Certificate Authority '$ca_name' not found."
echo "Available CAs:"
list_cas
echo ""
echo "Create a CA first with: $(basename "$0") -ca [$ca_name]"
exit 1
fi
# Use environment variables or default values
local country="${CERT_COUNTRY:-$DEFAULT_COUNTRY}"
local state="${CERT_STATE:-$DEFAULT_STATE}"
local locality="${CERT_LOCALITY:-$DEFAULT_LOCALITY}"
local organization="${CERT_ORG:-$DEFAULT_ORGANIZATION}"
local ou="${CERT_OU:-$DEFAULT_OU}"
local days="${CERT_DAYS:-$DEFAULT_CERT_DAYS}"
create_dirs
echo "Creating certificate for $domain..."
# Create the private key for the certificate
if [ "$USE_PASSWORD" = true ]; then
echo "Creating password-protected certificate private key..."
echo "You will be prompted to enter a password for the certificate private key."
openssl genrsa -des3 -out "$CERTS_DIR/$domain.key" 2048
else
echo "Creating certificate private key without password protection..."
openssl genrsa -out "$CERTS_DIR/$domain.key" 2048
fi
# Create a CSR configuration file
cat > "$CERTS_DIR/$domain.cnf" << EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = $country
ST = $state
L = $locality
O = $organization
OU = $ou
CN = $domain
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = $domain
DNS.2 = *.$domain
EOF
# Create the Certificate Signing Request (CSR)
openssl req -new -key "$CERTS_DIR/$domain.key" -out "$CERTS_DIR/$domain.csr" \
-config "$CERTS_DIR/$domain.cnf"
# Create the certificate extension file
cat > "$CERTS_DIR/$domain.ext" << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = $domain
DNS.2 = *.$domain
EOF
# Sign the CSR with the CA
openssl x509 -req -in "$CERTS_DIR/$domain.csr" \
-CA "$CA_DIR/$ca_name.crt" -CAkey "$CA_DIR/$ca_name.key" \
-out "$CERTS_DIR/$domain.crt" \
-extfile "$CERTS_DIR/$domain.ext" \
-days "$days" -sha256
# Copy the certificates to the current directory for easy access
cp "$CERTS_DIR/$domain.key" "./$domain.key"
cp "$CERTS_DIR/$domain.crt" "./$domain.crt"
echo "Certificate has been created:"
echo " - Private key: $domain.key"
echo " - Certificate: $domain.crt"
}
# Install a certificate (Linux only)
install_cert() {
if [ -z "$1" ]; then
echo "Error: Certificate type is required"
echo "Usage: $(basename "$0") -i <ca-name|domain>"
exit 1
fi
# Check if we're on Linux
if [ "$(uname)" != "Linux" ]; then
echo "Error: The -i option is only supported on Linux."
echo "For macOS or Windows, please follow the manual installation instructions:"
echo " $(basename "$0") -h"
exit 1
fi
# Check if we have the necessary permissions and tools
if ! command -v update-ca-certificates > /dev/null; then
echo "Error: update-ca-certificates command not found."
echo "Please install the ca-certificates package:"
echo " sudo apt-get install ca-certificates # For Debian/Ubuntu"
echo " sudo yum install ca-certificates # For RHEL/CentOS"
exit 1
fi
if [ ! -w "/usr/local/share/ca-certificates" ]; then
echo "Error: You need root permissions to install certificates."
echo "Please run this command with sudo:"
echo " sudo $(basename "$0") -i $1"
exit 1
fi
local cert_type="$1"
# First check if it's a CA
if [ -f "$CA_DIR/$cert_type.crt" ]; then
# It's a CA
echo "Installing CA certificate '$cert_type' into system trust store..."
cp "$CA_DIR/$cert_type.crt" "/usr/local/share/ca-certificates/$cert_type.crt"
update-ca-certificates
echo "CA certificate '$cert_type' has been installed successfully."
else
# Check if it's a domain certificate
if [ ! -f "$CERTS_DIR/$cert_type.crt" ]; then
echo "Error: Certificate for $cert_type not found."
echo "Available certificates:"
find "$CERTS_DIR" -name "*.crt" | sed -e 's|.*/||' -e 's|\.crt$||' | sort
echo ""
echo "Create the certificate first with: $(basename "$0") -cert $cert_type"
exit 1
fi
echo "Copying domain certificate to /etc/ssl/certs..."
cp "$CERTS_DIR/$cert_type.crt" "/etc/ssl/certs/$cert_type.pem"
echo "Certificate has been copied. Note that applications may need additional configuration."
fi
}
# Renew a certificate or CA
renew_cert() {
if [ -z "$1" ]; then
echo "Error: Certificate or CA name is required"
echo "Usage: $(basename "$0") -r <ca-name|domain>"
exit 1
fi
local name="$1"
# Check if it's a CA certificate
if [ -f "$CA_DIR/$name.key" ] && [ -f "$CA_DIR/$name.crt" ]; then
# Get the current CA expiration date
local expiry=$(openssl x509 -enddate -noout -in "$CA_DIR/$name.crt" | cut -d= -f 2)
local subject=$(openssl x509 -subject -noout -in "$CA_DIR/$name.crt" | sed 's/subject= //')
echo "Found Certificate Authority: $name"
echo "Subject: $subject"
echo "Current expiration date: $expiry"
echo ""
echo "WARNING: Renewing a CA certificate will require all certificates signed by this CA"
echo "to be re-issued. This operation cannot be undone."
echo ""
read -p "Do you want to renew this CA certificate? (y/N): " confirm
if [[ "$confirm" != [yY] && "$confirm" != [yY][eE][sS] ]]; then
echo "Operation cancelled."
exit 0
fi
# Get the current configuration
local days="${CA_DAYS:-$DEFAULT_CA_DAYS}"
# Backup the old CA files
local timestamp=$(date +%Y%m%d%H%M%S)
mkdir -p "$CA_DIR/backup"
cp "$CA_DIR/$name.key" "$CA_DIR/backup/$name.key.$timestamp"
cp "$CA_DIR/$name.crt" "$CA_DIR/backup/$name.crt.$timestamp"
cp "$CA_DIR/$name.cnf" "$CA_DIR/backup/$name.cnf.$timestamp" 2>/dev/null || true
echo "Creating renewed CA certificate..."
# Check if the key is password-protected
if openssl rsa -in "$CA_DIR/$name.key" -check -noout 2>/dev/null; then
echo "The CA private key is not password-protected."
else
echo "The CA private key is password-protected."
echo "You will be prompted to enter the password for the CA private key."
fi
# Create a new CA certificate using the existing key
if [ -f "$CA_DIR/$name.cnf" ]; then
# Use the existing configuration
openssl req -x509 -new -nodes -key "$CA_DIR/$name.key" -sha256 -days "$days" \
-out "$CA_DIR/$name.crt" -config "$CA_DIR/$name.cnf"
else
# Get environment variables or default values since we don't have the config
local country="${CERT_COUNTRY:-$DEFAULT_COUNTRY}"
local state="${CERT_STATE:-$DEFAULT_STATE}"
local locality="${CERT_LOCALITY:-$DEFAULT_LOCALITY}"
local organization="${CERT_ORG:-$DEFAULT_ORGANIZATION}"
local ou="${CERT_OU:-$DEFAULT_OU}"
local cn="${CA_CN:-$DEFAULT_CA_CN}"
# Create a new config file
cat > "$CA_DIR/$name.cnf" << EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
C = $country
ST = $state
L = $locality
O = $organization
OU = $ou
CN = $cn ($name)
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
EOF
# Create the renewed CA certificate
openssl req -x509 -new -nodes -key "$CA_DIR/$name.key" -sha256 -days "$days" \
-out "$CA_DIR/$name.crt" -config "$CA_DIR/$name.cnf"
fi
echo "Certificate Authority '$name' has been renewed:"
echo " - Private key: $CA_DIR/$name.key (unchanged)"
echo " - Certificate: $CA_DIR/$name.crt (renewed)"
echo " - Old certificate backed up: $CA_DIR/backup/$name.crt.$timestamp"
echo ""
echo "Don't forget to:"
echo "1. Re-install this CA certificate on your systems"
echo "2. Re-issue all certificates that were signed by this CA"
elif [ -f "$CERTS_DIR/$name.key" ] && [ -f "$CERTS_DIR/$name.crt" ]; then
# It's a domain certificate
# Get information about the certificate
local expiry=$(openssl x509 -enddate -noout -in "$CERTS_DIR/$name.crt" | cut -d= -f 2)
local subject=$(openssl x509 -subject -noout -in "$CERTS_DIR/$name.crt" | sed 's/subject= //')
local issuer=$(openssl x509 -issuer -noout -in "$CERTS_DIR/$name.crt" | sed 's/issuer= //')
# Try to determine which CA signed this certificate
local ca_name=""
for ca in $(find "$CA_DIR" -name "*.crt" | sed -e 's|.*/||' -e 's|\.crt$||'); do
local ca_subject=$(openssl x509 -subject -noout -in "$CA_DIR/$ca.crt" | sed 's/subject= //')
if [ "$ca_subject" = "$issuer" ]; then
ca_name="$ca"
break
fi
done
if [ -z "$ca_name" ]; then
# If we couldn't find the CA by subject, try to find it by checking the signature
for ca in $(find "$CA_DIR" -name "*.crt" | sed -e 's|.*/||' -e 's|\.crt$||'); do
if openssl verify -CAfile "$CA_DIR/$ca.crt" "$CERTS_DIR/$name.crt" > /dev/null 2>&1; then
ca_name="$ca"
break
fi
done
fi
if [ -z "$ca_name" ]; then
echo "Error: Could not determine which CA signed this certificate."
echo "Available CAs:"
list_cas
echo ""
read -p "Enter the CA name that signed this certificate: " ca_name
if [ ! -f "$CA_DIR/$ca_name.key" ] || [ ! -f "$CA_DIR/$ca_name.crt" ]; then
echo "Error: CA '$ca_name' not found."
exit 1
fi
fi
echo "Found certificate: $name"
echo "Subject: $subject"
echo "Issuer: $issuer"
echo "Current expiration date: $expiry"
echo "Signed by CA: $ca_name"
echo ""
read -p "Do you want to renew this certificate? (y/N): " confirm
if [[ "$confirm" != [yY] && "$confirm" != [yY][eE][sS] ]]; then
echo "Operation cancelled."
exit 0
fi
# Backup the old certificate
local timestamp=$(date +%Y%m%d%H%M%S)
mkdir -p "$CERTS_DIR/backup"
cp "$CERTS_DIR/$name.key" "$CERTS_DIR/backup/$name.key.$timestamp" 2>/dev/null || true
cp "$CERTS_DIR/$name.crt" "$CERTS_DIR/backup/$name.crt.$timestamp" 2>/dev/null || true
cp "$CERTS_DIR/$name.csr" "$CERTS_DIR/backup/$name.csr.$timestamp" 2>/dev/null || true
cp "$CERTS_DIR/$name.cnf" "$CERTS_DIR/backup/$name.cnf.$timestamp" 2>/dev/null || true
cp "$CERTS_DIR/$name.ext" "$CERTS_DIR/backup/$name.ext.$timestamp" 2>/dev/null || true
# Check if the certificate key is password-protected
if openssl rsa -in "$CERTS_DIR/$name.key" -check -noout 2>/dev/null; then
echo "The certificate private key is not password-protected."
else
echo "The certificate private key is password-protected."
echo "You will be prompted to enter the password for the certificate private key."
fi
# Check if the CA key is password-protected
if openssl rsa -in "$CA_DIR/$ca_name.key" -check -noout 2>/dev/null; then
echo "The CA private key is not password-protected."
else
echo "The CA private key is password-protected."
echo "You will be prompted to enter the password for the CA private key."
fi
# Use existing configuration if possible
if [ -f "$CERTS_DIR/$name.cnf" ] && [ -f "$CERTS_DIR/$name.ext" ]; then
echo "Renewing certificate using existing configuration..."
# Create a new CSR using the existing key and config
openssl req -new -key "$CERTS_DIR/$name.key" -out "$CERTS_DIR/$name.csr" \
-config "$CERTS_DIR/$name.cnf"
# Sign the new CSR with the CA
local days="${CERT_DAYS:-$DEFAULT_CERT_DAYS}"
openssl x509 -req -in "$CERTS_DIR/$name.csr" \
-CA "$CA_DIR/$ca_name.crt" -CAkey "$CA_DIR/$ca_name.key" \
-out "$CERTS_DIR/$name.crt" \
-extfile "$CERTS_DIR/$name.ext" \
-days "$days" -sha256
# Copy the renewed certificate to the current directory
cp "$CERTS_DIR/$name.crt" "./$name.crt"
echo "Certificate for '$name' has been renewed:"
echo " - Private key: $name.key (unchanged)"
echo " - Certificate: $name.crt (renewed)"
echo " - Old certificate backed up: $CERTS_DIR/backup/$name.crt.$timestamp"
else
echo "Error: Cannot find required configuration files for renewal."
echo "You may need to re-create the certificate from scratch:"
echo " $(basename "$0") -cert $name $ca_name"
exit 1
fi
else
echo "Error: Certificate or CA '$name' not found."
echo ""
echo "Available CAs:"
list_cas
echo ""
echo "Available certificates:"
find "$CERTS_DIR" -name "*.crt" | sed -e 's|.*/||' -e 's|\.crt$||' | sort
exit 1
fi
}
# Remove password from an existing key
remove_password() {
if [ -z "$1" ]; then
echo "Error: Certificate or CA name is required"
echo "Usage: $(basename "$0") -rmpw <ca-name|domain>"
exit 1
fi
local name="$1"
local key_path=""
local backup_dir=""
# Check if it's a CA key
if [ -f "$CA_DIR/$name.key" ]; then
key_path="$CA_DIR/$name.key"
backup_dir="$CA_DIR/backup"
echo "Found CA key: $key_path"
# Check if it's a certificate key
elif [ -f "$CERTS_DIR/$name.key" ]; then
key_path="$CERTS_DIR/$name.key"
backup_dir="$CERTS_DIR/backup"
echo "Found certificate key: $key_path"
else
echo "Error: Key for '$name' not found."
echo ""
echo "Available CAs:"
list_cas
echo ""
echo "Available certificates:"
find "$CERTS_DIR" -name "*.key" | sed -e 's|.*/||' -e 's|\.key$||' | sort
exit 1
fi
# Check if the key is already unprotected
if openssl rsa -in "$key_path" -check -noout 2>/dev/null; then
echo "The key is already not password-protected."
exit 0
fi
echo "This key is password-protected."
echo "You will be prompted to enter the current password."
echo ""
echo "WARNING: Removing the password from a key reduces its security."
echo "Anyone with access to the key file will be able to use it without a password."
echo ""
read -p "Do you want to continue? (y/N): " confirm
if [[ "$confirm" != [yY] && "$confirm" != [yY][eE][sS] ]]; then
echo "Operation cancelled."
exit 0
fi
# Backup the original key
local timestamp=$(date +%Y%m%d%H%M%S)
mkdir -p "$backup_dir"
cp "$key_path" "$backup_dir/$(basename "$key_path").$timestamp"
# Create a temporary key file
local temp_key="${key_path}.temp"
# Remove the password
openssl rsa -in "$key_path" -out "$temp_key"
# Replace the original key with the unprotected one
mv "$temp_key" "$key_path"
echo "Password has been removed from the key."
echo "Original key backed up to: $backup_dir/$(basename "$key_path").$timestamp"
}
# Main program
case "$1" in
-h|--help)
show_help
;;
-nopw)
USE_PASSWORD=false
shift
if [ -z "$1" ]; then
echo "Error: -nopw must be followed by another command"
echo "Example: $(basename "$0") -nopw -ca mycompany"
exit 1
fi
case "$1" in
-ca)
create_ca "$2"
;;
-cert)
create_cert "$2" "$3"
;;
-r)
renew_cert "$2"
;;
-rmpw)
remove_password "$2"
;;
*)
echo "Error: -nopw can only be used with -ca, -cert, or -r"
exit 1
;;
esac
;;
-ca)
create_ca "$2"
;;
-cert)
create_cert "$2" "$3"
;;
-i)
install_cert "$2"
;;
-list)
list_cas
;;
-r)
renew_cert "$2"
;;
-rmpw)
remove_password "$2"
;;
*)
echo "Unknown parameter: $1"
echo "Use -h or --help for help."
exit 1
;;
esac
exit 0
@sames
Copy link
Author

sames commented Feb 28, 2025

Here's a summary of the certhelper.sh script and its functions:

Files and Directories

  1. Main directories:

    • ./ca/ - Storage location for all Certificate Authority (CA) files
    • ./certs/ - Storage location for all domain certificates
    • ./ca/backup/ - Backups of renewed CA certificates
    • ./certs/backup/ - Backups of renewed domain certificates
  2. CA files (for each CA with name <name>):

    • ca/<name>.key - Private key of the CA
    • ca/<name>.crt - Public certificate of the CA
    • ca/<name>.cnf - OpenSSL configuration for the CA
    • ca/<name>.srl - Serial number for signed certificates
  3. Domain certificate files (for each domain <domain>):

    • certs/<domain>.key - Private key
    • certs/<domain>.crt - Public certificate
    • certs/<domain>.csr - Certificate Signing Request
    • certs/<domain>.cnf - OpenSSL configuration for this domain
    • certs/<domain>.ext - Extension file for the certificate
    • A copy of .key and .crt in the current directory for easy access
  4. System installation locations:

    • Linux: CA certificate in /usr/local/share/ca-certificates/<name>.crt
    • Linux: Domain certificate in /etc/ssl/certs/<domain>.pem
    • MacOS: CA certificate imported into Keychain Access (System keychain)
    • Windows: CA certificate installed in "Trusted Root Certification Authorities"

Using the Script

  1. Create a CA:

    ./certhelper.sh -ca mycompany

    Creates a new CA named "mycompany" (or "rootca" as default if no name is specified)

  2. Create a certificate:

    ./certhelper.sh -cert nas.lan mycompany

    Creates a certificate for "nas.lan", signed by the CA "mycompany"

  3. Install a CA on the system (Linux only):

    sudo ./certhelper.sh -i mycompany

    Installs the CA in the system trust store and updates CA certificates

  4. List CAs:

    ./certhelper.sh -list

    Shows all available CAs with their subjects

  5. Renew a certificate or CA:

    ./certhelper.sh -r nas.lan

    or

    ./certhelper.sh -r mycompany

    Renews either a domain certificate or a CA with backup of the old files

  6. Show help:

    ./certhelper.sh -h

    Shows detailed help and installation instructions for different operating systems

Installation Notes by Operating System

  1. Linux:

    • The -i option copies CA certificates to /usr/local/share/ca-certificates/ and runs update-ca-certificates
    • Domain certificates are copied to /etc/ssl/certs/
  2. macOS:

    • Open CA certificate with Keychain Access
    • Add to System keychain
    • Set to "Always Trust"
  3. Windows:

    • Either via GUI installation or PowerShell command:
    • Import-Certificate -FilePath ca\mycompany.crt -CertStoreLocation Cert:\LocalMachine\Root

The script organizes all certificates and CAs neatly and allows for using multiple CAs for different purposes. It facilitates management through functions like renewal, backup, and verification of whether files already exist.

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