diff --git a/federation/README.md b/federation/README.md index 0414b36..5db42fb 100644 --- a/federation/README.md +++ b/federation/README.md @@ -98,7 +98,7 @@ respectively), and the system looks like this: | | 172.50.88 | | | +-----------+ | +----------------172.50.0.0/24----------------+ - fd23:0d79:d076::/64 + fd23:0d79:d076::/64 ``` ### Removing a node from the network @@ -144,7 +144,7 @@ Here's what the script creates: * Intermediate CA certificate (signed by Root CA) * Two server certificates with OCSP information (one for each Openfire instance) * An OCSP responder certificate (for signing OCSP responses) -* Full certificate chains for both servers (server + intermediate + root) +* Full certificate chains for each XMPP server (server + intermediate + root) * Certificate database (index.txt) for the OCSP responder to track certificate statuses All certificates are stored in `./_data/certs/`. @@ -174,14 +174,56 @@ All certificates are stored in `./_data/certs/`. This setup allows certificates to be checked for revocation status making a request to the OCSP responder: ```bash -```bash openssl ocsp -url http://localhost:8888 \ - -issuer _data/certs/ca/intermediate-ca/intermediate.crt \ - -CAfile _data/certs/chain1.pem \ - -cert _data/certs/server1.crt \ - -text + -issuer _data/certs/ca/intermediate-ca/intermediate.crt \ + -CAfile _data/certs/xmpp1_chain.pem \ + -cert _data/certs/xmpp1.crt \ + -text ``` +### Certificate Revocation + +The `revocation.sh` script allows you to revoke SSL certificates and +update the OCSP responder's database. You can also un-revoke certificates +that were previously revoked. + +```bash +./revocation.sh --server xmpp1 [--reason reason] [--unrevoke] +``` + +Available revocation reasons: +- unspecified (default) +- keyCompromise +- CACompromise +- affiliationChanged +- superseded +- cessationOfOperation +- certificateHold + +Examples: +```bash +# Revoke xmpp1's certificate +./revocation.sh --server xmpp1 + +# Revoke with specific reason +./revocation.sh --server xmpp1 --reason keyCompromise + +# Remove revocation status +./revocation.sh --server xmpp1 --unrevoke +``` + +To verify the current status: +```bash +openssl ocsp -url http://localhost:8888 \ + -issuer _data/certs/ca/intermediate-ca/intermediate.crt \ + -CAfile _data/certs/xmpp1_chain.pem \ + -cert _data/certs/xmpp1.crt \ + -text +``` + +Note: The first OCSP status check may return the previous status. Run +the check again if this happens - subsequent checks will show the +current status. ## How it's built diff --git a/federation/docker-compose-ocsp-responder.yml b/federation/docker-compose-ocsp-responder.yml index bff5e28..7b402cc 100644 --- a/federation/docker-compose-ocsp-responder.yml +++ b/federation/docker-compose-ocsp-responder.yml @@ -17,8 +17,8 @@ services: # ---------------------- # openssl ocsp -url http://ocsp.localhost.example:8888 \ # -issuer _data/certs/ca/intermediate-ca/intermediate.crt \ - # -CAfile _data/certs/chain1.pem \ - # -cert _data/certs/server1.crt \ + # -CAfile _data/certs/xmpp1.pem \ + # -cert _data/certs/xmpp1.crt \ # -text ocsp-responder: image: alpine:latest diff --git a/federation/scripts/generate-certificates.sh b/federation/scripts/generate-certificates.sh index bcd2b1b..7f7b954 100755 --- a/federation/scripts/generate-certificates.sh +++ b/federation/scripts/generate-certificates.sh @@ -9,6 +9,12 @@ OCSP_URL="http://ocsp.localhost.example:8888" CERT_DIR="./_data/certs" XMPP_BASE_DIR="./_data/xmpp" +# Check if OpenSSL is installed +if ! command -v openssl &> /dev/null; then + echo "Error: OpenSSL is not installed" + exit 1 +fi + # Function to check which server directories exist get_server_instances() { local instances=() diff --git a/federation/scripts/import-certificates.sh b/federation/scripts/import-certificates.sh index 0a1729c..671e055 100755 --- a/federation/scripts/import-certificates.sh +++ b/federation/scripts/import-certificates.sh @@ -9,6 +9,12 @@ KEYSTORE_PASSWORD="changeit" CERT_DIR="./_data/certs" XMPP_BASE_DIR="./_data/xmpp" +# Check if OpenSSL is installed +if ! command -v openssl &> /dev/null; then + echo "Error: OpenSSL is not installed" + exit 1 +fi + # Function to check which server directories exist get_server_instances() { local instances=() diff --git a/federation/scripts/revocation.sh b/federation/scripts/revocation.sh new file mode 100755 index 0000000..c96419c --- /dev/null +++ b/federation/scripts/revocation.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +# Configuration +CERT_DIR="./_data/certs" +INDEX_FILE="${CERT_DIR}/ca/intermediate-ca/index.txt" +CA_CERT="${CERT_DIR}/ca/intermediate-ca/intermediate.crt" +CA_KEY="${CERT_DIR}/ca/intermediate-ca/private/intermediate.key" + +# Default revocation reason +REASON="unspecified" +FOUND_CERT=false +ACTION="revoke" # Default action + +# Usage information +usage() { + echo "Usage: $0 [--server servername] [--cert certificate_file] [--reason reason_code] [--unrevoke]" + echo "Revokes or unrevokes an SSL certificate and updates the OCSP database" + echo "" + echo "Options:" + echo " --server Server name (e.g., xmpp1)" + echo " --cert Path to the certificate to revoke (alternative to --server)" + echo " --reason Reason for revocation (optional):" + echo " unspecified (default)" + echo " keyCompromise" + echo " CACompromise" + echo " affiliationChanged" + echo " superseded" + echo " cessationOfOperation" + echo " certificateHold" + echo " --unrevoke Removes the revocation status of the certificate" + exit 1 +} + +# Parse command line options +while [[ $# -gt 0 ]]; do + case $1 in + --server) + SERVER_NAME="$2" + if [[ ! "$SERVER_NAME" =~ ^xmpp[0-9]+$ ]]; then + echo "Error: Server name must be in format 'xmpp' (e.g., xmpp1)" + usage + fi + CERTIFICATE="${CERT_DIR}/${SERVER_NAME}.crt" + shift 2 + ;; + --cert) + CERTIFICATE="$2" + shift 2 + ;; + --reason) + case "$2" in + unspecified|keyCompromise|CACompromise|affiliationChanged|superseded|cessationOfOperation|certificateHold) + REASON="$2" + ;; + *) + echo "Error: Invalid reason. See usage for valid reasons." + usage + ;; + esac + shift 2 + ;; + --unrevoke) + ACTION="unrevoke" + shift + ;; + -h|--help) + usage + ;; + *) + echo "Error: Unknown option $1" + usage + ;; + esac +done + +# Validate input and files +if [ -z "$CERTIFICATE" ]; then + echo "Error: Either --server or --cert must be specified" + usage +fi + +for file in "$CERTIFICATE" "$INDEX_FILE" "$CA_CERT" "$CA_KEY"; do + if [ ! -f "$file" ]; then + echo "Error: Required file not found: $file" + exit 1 + fi +done + +# Create backup +INDEX_BACKUP="${INDEX_FILE}.$(date +%Y%m%d%H%M%S).bak" +cp "$INDEX_FILE" "$INDEX_BACKUP" + +# Get certificate serial number +SERIAL=$(openssl x509 -in "$CERTIFICATE" -noout -serial | cut -d'=' -f2) + +# Create new index file +> "$INDEX_FILE.new" + +# Read and process each line +while read -r line; do + # Split the line into fields + status=$(echo "$line" | cut -f1) + expiry=$(echo "$line" | cut -f2) + revocation=$(echo "$line" | cut -f3) + serial=$(echo "$line" | cut -f4) + filename=$(echo "$line" | cut -f5) + subject=$(echo "$line" | cut -f6) + + if [ "$serial" = "$SERIAL" ]; then + if [ "$ACTION" = "revoke" ]; then + if [ "$status" = "R" ]; then + echo "Error: Certificate is already revoked" + rm "$INDEX_FILE.new" + rm "$INDEX_BACKUP" + exit 1 + fi + # Create revoked entry + REVOKE_DATE=$(date -u +%y%m%d%H%M%SZ) + printf 'R\t%s\t%s,%s\t%s\t%s\t%s\n' \ + "$expiry" \ + "$REVOKE_DATE" \ + "$REASON" \ + "$serial" \ + "$filename" \ + "$subject" >> "$INDEX_FILE.new" + else # unrevoke + if [ "$status" != "R" ]; then + echo "Error: Certificate is not revoked" + rm "$INDEX_FILE.new" + rm "$INDEX_BACKUP" + exit 1 + fi + # Convert back to valid entry + printf 'V\t%s\t\t%s\t%s\t%s\n' \ + "$expiry" \ + "$serial" \ + "$filename" \ + "$subject" >> "$INDEX_FILE.new" + fi + FOUND_CERT=true + else + # Not our certificate - keep original line + echo "$line" >> "$INDEX_FILE.new" + fi +done < "$INDEX_FILE" + +if [ "$FOUND_CERT" = false ]; then + echo "Error: Certificate not found in database" + echo "Looking for serial: $SERIAL" + rm "$INDEX_FILE.new" + exit 1 +fi + +if mv "$INDEX_FILE.new" "$INDEX_FILE"; then + if [ "$ACTION" = "revoke" ]; then + echo "Certificate successfully revoked" + echo "Reason: $REASON" + else + echo "Certificate successfully unrevoked" + fi + echo -e "\nTo verify the current status:" + echo "openssl ocsp -url http://ocsp.localhost.example:8888 \\" + echo " -issuer ${CERT_DIR}/ca/intermediate-ca/intermediate.crt \\" + echo " -CAfile ${CERT_DIR}/$(basename "$CERTIFICATE" .crt)_chain.pem \\" + echo " -cert ${CERTIFICATE} \\" + echo " -text" + echo -e "\nNote: The first OCSP status check may return the previous status." + echo " Run the check again if this happens - subsequent checks will show the current status." + # Clean up backup file on success + rm "$INDEX_BACKUP" +else + echo "Error: Failed to ${ACTION} certificate" + echo "Restoring database backup..." + cp "$INDEX_BACKUP" "$INDEX_FILE" + exit 1 +fi \ No newline at end of file