feat: Support certificate revocation
parent
a99d37d2e4
commit
5f80851d44
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=()
|
||||
|
|
|
@ -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=()
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue