feat: Cert generation for multiple xmpp nodes

Cert generation and import scripts now support any number of XMPP servers and use more intuitive naming for the certificates.

 This will make it easier to move cert generation to other configurations. Maybe promoting this to a top-level script to generate certs in all scenarios.
fix-revocation-examples
Matthew Vivian 2024-11-13 08:36:03 +00:00 committed by Guus der Kinderen
parent 4c608f22f8
commit 5a595cd864
2 changed files with 116 additions and 46 deletions

View File

@ -7,6 +7,23 @@ OCSP_URL="http://ocsp.localhost.example:8888"
# Base directory for all certificate-related files
# All paths in this script will be relative to this directory
CERT_DIR="./_data/certs"
XMPP_BASE_DIR="./_data/xmpp"
# Function to check which server directories exist
get_server_instances() {
local instances=()
# Look for numbered directories in the xmpp base directory
for dir in "$XMPP_BASE_DIR"/*/; do
if [[ -d "$dir" ]]; then
# Extract the number from the directory name
local num=$(basename "$dir")
if [[ "$num" =~ ^[0-9]+$ ]]; then
instances+=("$num")
fi
fi
done
echo "${instances[@]}"
}
# Create the PKI directory structure:
# We only need:
@ -53,15 +70,16 @@ openssl x509 -req -in "${CERT_DIR}/ca/intermediate-ca/intermediate.csr" \
# Function to generate a server certificate and add it to the certificate database
# Parameters:
# $1: instance number (1 or 2 for xmpp1/xmpp2)
# $1: instance number (1, 2, or 3 for xmpp1/xmpp2/xmpp3)
generate_server_cert() {
local instance=$1
local server_name="xmpp${instance}"
# Generate server private key and CSR
openssl genrsa -out "${CERT_DIR}/server${instance}.key" 2048
openssl genrsa -out "${CERT_DIR}/${server_name}.key" 2048
# Create OpenSSL config file for SAN support
cat > "${CERT_DIR}/server${instance}.cnf" << EOF
cat > "${CERT_DIR}/${server_name}.cnf" << EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
@ -72,7 +90,7 @@ C = GB
ST = London
L = London
O = Test Openfire
CN = xmpp${instance}.localhost.example
CN = ${server_name}.localhost.example
[v3_req]
basicConstraints = CA:FALSE
@ -81,17 +99,17 @@ extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = xmpp${instance}.localhost.example
DNS.2 = *.xmpp${instance}.localhost.example
DNS.1 = ${server_name}.localhost.example
DNS.2 = *.${server_name}.localhost.example
EOF
# Generate CSR with the config file
openssl req -new -key "${CERT_DIR}/server${instance}.key" \
-out "${CERT_DIR}/server${instance}.csr" \
-config "${CERT_DIR}/server${instance}.cnf"
openssl req -new -key "${CERT_DIR}/${server_name}.key" \
-out "${CERT_DIR}/${server_name}.csr" \
-config "${CERT_DIR}/${server_name}.cnf"
# Create OpenSSL config for certificate signing
cat > "${CERT_DIR}/server${instance}_sign.cnf" << EOF
cat > "${CERT_DIR}/${server_name}_sign.cnf" << EOF
basicConstraints = critical,CA:false
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
@ -99,31 +117,33 @@ subjectAltName = @alt_names
authorityInfoAccess = OCSP;URI:${OCSP_URL}
[alt_names]
DNS.1 = xmpp${instance}.localhost.example
DNS.2 = *.xmpp${instance}.localhost.example
DNS.1 = ${server_name}.localhost.example
DNS.2 = *.${server_name}.localhost.example
EOF
# Sign the server certificate with the Intermediate CA
openssl x509 -req -in "${CERT_DIR}/server${instance}.csr" \
openssl x509 -req -in "${CERT_DIR}/${server_name}.csr" \
-CA "${CERT_DIR}/ca/intermediate-ca/intermediate.crt" \
-CAkey "${CERT_DIR}/ca/intermediate-ca/private/intermediate.key" -CAcreateserial \
-out "${CERT_DIR}/server${instance}.crt" -days 365 \
-extfile "${CERT_DIR}/server${instance}_sign.cnf"
-out "${CERT_DIR}/${server_name}.crt" -days 365 \
-extfile "${CERT_DIR}/${server_name}_sign.cnf"
# Create the full certificate chain
cat "${CERT_DIR}/server${instance}.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt" "${CERT_DIR}/ca/root-ca/ca.crt" > "${CERT_DIR}/chain${instance}.pem"
cat "${CERT_DIR}/${server_name}.crt" \
"${CERT_DIR}/ca/intermediate-ca/intermediate.crt" \
"${CERT_DIR}/ca/root-ca/ca.crt" > "${CERT_DIR}/${server_name}_chain.pem"
# Add to certificate database
SERIAL=$(openssl x509 -in "${CERT_DIR}/server${instance}.crt" -noout -serial | cut -d'=' -f2)
SUBJECT=$(openssl x509 -in "${CERT_DIR}/server${instance}.crt" -noout -subject | cut -d'=' -f2-)
SERIAL=$(openssl x509 -in "${CERT_DIR}/${server_name}.crt" -noout -serial | cut -d'=' -f2)
SUBJECT=$(openssl x509 -in "${CERT_DIR}/${server_name}.crt" -noout -subject | cut -d'=' -f2-)
printf 'V\t%s\t\t%s\tunknown\t%s\n' "$(date -u +%y%m%d%H%M%SZ)" "$SERIAL" "$SUBJECT" >> "${CERT_DIR}/ca/intermediate-ca/index.txt"
# Clean up temporary config files
rm -f "${CERT_DIR}/server${instance}.cnf" "${CERT_DIR}/server${instance}_sign.cnf"
rm -f "${CERT_DIR}/${server_name}.cnf" "${CERT_DIR}/${server_name}_sign.cnf"
# Display the certificate's subject and SANs for verification
echo "Certificate generated for instance ${instance}:"
openssl x509 -in "${CERT_DIR}/server${instance}.crt" -noout -subject -ext subjectAltName
echo "Certificate generated for ${server_name}:"
openssl x509 -in "${CERT_DIR}/${server_name}.crt" -noout -subject -ext subjectAltName
}
# Generate the OCSP responder certificate
@ -144,17 +164,36 @@ openssl x509 -req -in "${CERT_DIR}/ca/ocsp-responder/ocsp.csr" \
-out "${CERT_DIR}/ca/ocsp-responder/ocsp.crt" -days 365 \
-extfile <(printf 'basicConstraints=critical,CA:false\nkeyUsage=critical,digitalSignature\nextendedKeyUsage=OCSPSigning')
# Generate certificates for both Openfire instances
generate_server_cert 1
generate_server_cert 2
# Get the list of server instances that exist
SERVER_INSTANCES=($(get_server_instances))
if [ ${#SERVER_INSTANCES[@]} -eq 0 ]; then
echo "Error: No server directories found in ${XMPP_BASE_DIR}"
exit 1
fi
echo "Found server directories for instances: ${SERVER_INSTANCES[*]}"
# Generate certificates for each existing server instance
for instance in "${SERVER_INSTANCES[@]}"; do
echo "Generating certificates for xmpp${instance}"
generate_server_cert "$instance"
done
# Verify the certificate chain for all generated certificates
# This ensures that all certificates are properly signed and trusted
echo "Verifying certificates..."
openssl verify -CAfile "${CERT_DIR}/ca/root-ca/ca.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt"
openssl verify -CAfile <(cat "${CERT_DIR}/ca/root-ca/ca.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt") "${CERT_DIR}/server1.crt"
openssl verify -CAfile <(cat "${CERT_DIR}/ca/root-ca/ca.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt") "${CERT_DIR}/server2.crt"
openssl verify -CAfile <(cat "${CERT_DIR}/ca/root-ca/ca.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt") "${CERT_DIR}/ca/ocsp-responder/ocsp.crt"
# Verify each server certificate
for instance in "${SERVER_INSTANCES[@]}"; do
openssl verify -CAfile <(cat "${CERT_DIR}/ca/root-ca/ca.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt") \
"${CERT_DIR}/xmpp${instance}.crt"
done
openssl verify -CAfile <(cat "${CERT_DIR}/ca/root-ca/ca.crt" "${CERT_DIR}/ca/intermediate-ca/intermediate.crt") \
"${CERT_DIR}/ca/ocsp-responder/ocsp.crt"
printf '\nCertificate generation complete.'
printf '\nOCSP URL configured as: %s\n\n' "$OCSP_URL"
printf '\nOCSP URL configured as: %s\n' "$OCSP_URL"
printf 'Generated certificates for servers: %s\n\n' "${SERVER_INSTANCES[*]}"

View File

@ -7,17 +7,35 @@ KEYSTORE_PASSWORD="changeit"
# Base directory where certificates were generated
# This should match the CERT_DIR from the certificate generation script
CERT_DIR="./_data/certs"
XMPP_BASE_DIR="./_data/xmpp"
# Function to check which server directories exist
get_server_instances() {
local instances=()
# Look for numbered directories in the xmpp base directory
for dir in "$XMPP_BASE_DIR"/*/; do
if [[ -d "$dir" ]]; then
# Extract the number from the directory name
local num=$(basename "$dir")
if [[ "$num" =~ ^[0-9]+$ ]]; then
instances+=("$num")
fi
fi
done
echo "${instances[@]}"
}
# Function to import certificates and set up keystores/truststores for one Openfire instance
# Parameters:
# $1: instance number (1 or 2 for xmpp1/xmpp2)
# $1: instance number (1, 2, or 3 for xmpp1/xmpp2/xmpp3)
import_certificates() {
local instance=$1
local server_name="xmpp${instance}"
# Directory where Openfire expects to find its certificates
local conf_dir="_data/xmpp/${instance}/conf/security"
echo "Importing certificates for Openfire instance ${instance}..."
echo "Importing certificates for ${server_name}..."
# Ensure the security directory exists
mkdir -p "${conf_dir}"
@ -25,7 +43,7 @@ import_certificates() {
# Remove any existing keystore to start fresh
rm -f "${conf_dir}/keystore"
echo "Creating new keystore for instance ${instance}"
echo "Creating new keystore for ${server_name}"
# Create a new empty keystore by generating and immediately deleting a temporary keypair
# This ensures the keystore is properly initialized with the correct format
keytool -genkeypair \
@ -46,12 +64,12 @@ import_certificates() {
# First convert them to PKCS12 format which can be imported into a Java keystore
echo "Importing server certificate and private key..."
openssl pkcs12 -export \
-in "${CERT_DIR}/server${instance}.crt" \
-inkey "${CERT_DIR}/server${instance}.key" \
-in "${CERT_DIR}/${server_name}.crt" \
-inkey "${CERT_DIR}/${server_name}.key" \
-chain \
-CAfile "${CERT_DIR}/chain${instance}.pem" \
-name "xmpp${instance}.localhost.example" \
-out "${CERT_DIR}/server${instance}.p12" \
-CAfile "${CERT_DIR}/${server_name}_chain.pem" \
-name "${server_name}.localhost.example" \
-out "${CERT_DIR}/${server_name}.p12" \
-password "pass:${KEYSTORE_PASSWORD}"
# Import the PKCS12 file into the keystore
@ -59,15 +77,15 @@ import_certificates() {
-deststorepass "${KEYSTORE_PASSWORD}" \
-destkeypass "${KEYSTORE_PASSWORD}" \
-destkeystore "${conf_dir}/keystore" \
-srckeystore "${CERT_DIR}/server${instance}.p12" \
-srckeystore "${CERT_DIR}/${server_name}.p12" \
-srcstoretype PKCS12 \
-srcstorepass "${KEYSTORE_PASSWORD}" \
-alias "xmpp${instance}.localhost.example"
-alias "${server_name}.localhost.example"
# Create or update truststore
# truststore - used by the server to verify other servers
if [ ! -f "${conf_dir}/truststore" ]; then
echo "Creating new truststore for instance ${instance}"
echo "Creating new truststore for ${server_name}"
# Initialize a new truststore with a dummy entry
keytool -importpass \
-keystore "${conf_dir}/truststore" \
@ -106,21 +124,34 @@ import_certificates() {
echo "Intermediate CA already exists in truststore"
fi
echo "Certificate import completed for instance ${instance}"
echo "Certificate import completed for ${server_name}"
}
# Main script execution
echo "Starting certificate import process..."
# Import certificates for both Openfire instances
import_certificates 1
import_certificates 2
# Get the list of server instances that exist
SERVER_INSTANCES=($(get_server_instances))
if [ ${#SERVER_INSTANCES[@]} -eq 0 ]; then
echo "Error: No server directories found in ${XMPP_BASE_DIR}"
exit 1
fi
echo "Found server directories for instances: ${SERVER_INSTANCES[*]}"
# Import certificates for each existing server instance
for instance in "${SERVER_INSTANCES[@]}"; do
echo "Importing certificates for xmpp${instance}"
import_certificates "$instance"
done
# Clean up temporary PKCS12 files that were created during the import process
rm -f "${CERT_DIR}"/*.p12
# Display commands that can be used to verify the keystore contents
echo -e "\nTo verify the keystores, run:"
echo "keytool -list -keystore _data/xmpp/1/conf/security/keystore -storepass ${KEYSTORE_PASSWORD}"
echo "keytool -list -keystore _data/xmpp/1/conf/security/truststore -storepass ${KEYSTORE_PASSWORD}"
for instance in "${SERVER_INSTANCES[@]}"; do
echo "keytool -list -keystore _data/xmpp/${instance}/conf/security/keystore -storepass ${KEYSTORE_PASSWORD}"
echo "keytool -list -keystore _data/xmpp/${instance}/conf/security/truststore -storepass ${KEYSTORE_PASSWORD}"
done