feat: Support certificate revocation

fix-revocation-examples
Matthew Vivian 2024-11-13 16:14:04 +00:00 committed by Guus der Kinderen
parent a99d37d2e4
commit 5f80851d44
5 changed files with 239 additions and 9 deletions

View File

@ -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

View File

@ -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

View File

@ -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=()

View File

@ -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=()

View File

@ -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<number>' (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