Skip to content

Instantly share code, notes, and snippets.

@sireza
Created October 9, 2025 02:58
Show Gist options
  • Save sireza/eb2d2e166c510a333893a962681e9cd2 to your computer and use it in GitHub Desktop.
Save sireza/eb2d2e166c510a333893a962681e9cd2 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Script to fetch SSL certificate chain from a URL and create a PKCS12 keystore
# Usage: ./ssl-cert-to-keystore.sh <URL>
set -e # Exit on any error
# Function to display usage
usage() {
echo "Usage: $0 <URL>"
echo "Example: $0 google.com"
echo " $0 https://example.com"
exit 1
}
# Function to check if Java is installed
check_java() {
echo "Checking Java Runtime Environment..."
# Check if java command is available
if ! command -v java >/dev/null 2>&1; then
echo "Error: Java Runtime Environment (JRE/JDK) is not installed or not in PATH"
echo "keytool requires Java Runtime Environment to function"
echo ""
echo "Please install one of the following:"
echo " - Java JDK (includes JRE + development tools)"
echo " - Java JRE (runtime only, sufficient for keytool)"
echo ""
echo "Download options:"
echo " - OpenJDK: https://adoptium.net/"
echo " - Oracle Java: https://www.oracle.com/java/"
echo " - Amazon Corretto: https://aws.amazon.com/corretto/"
exit 1
fi
# Test Java runtime functionality
if ! java -version >/dev/null 2>&1; then
echo "Error: Java runtime is not functioning properly"
echo "Please reinstall Java Runtime Environment (JRE/JDK)"
exit 1
fi
# Get and display Java version information
JAVA_VERSION=$(java -version 2>&1 | head -n 1)
JAVA_RUNTIME_INFO=$(java -version 2>&1 | grep -i "runtime\|vm\|jre\|jdk" | head -n 1 || echo "")
echo "✓ Java Runtime found: $JAVA_VERSION"
if [ -n "$JAVA_RUNTIME_INFO" ]; then
echo " Runtime info: $JAVA_RUNTIME_INFO"
fi
# Check if keytool is available
if ! command -v keytool >/dev/null 2>&1; then
echo "Warning: keytool command not found in PATH"
echo "Attempting to locate keytool in common Java installation directories..."
# Common keytool locations
KEYTOOL_LOCATIONS=(
"$JAVA_HOME/bin/keytool"
"/usr/bin/keytool"
"/usr/local/bin/keytool"
"$(dirname "$(command -v java)")/keytool"
)
KEYTOOL_FOUND=false
for location in "${KEYTOOL_LOCATIONS[@]}"; do
if [ -f "$location" ] && [ -x "$location" ]; then
echo "✓ Found keytool at: $location"
# Update PATH to include keytool location if needed
KEYTOOL_DIR=$(dirname "$location")
if [[ ":$PATH:" != *":$KEYTOOL_DIR:"* ]]; then
export PATH="$KEYTOOL_DIR:$PATH"
echo " Added to PATH: $KEYTOOL_DIR"
fi
KEYTOOL_FOUND=true
break
fi
done
if [ "$KEYTOOL_FOUND" = false ]; then
echo "Error: keytool not found"
echo "keytool is required and should be included with Java installations"
echo ""
echo "Solutions:"
echo " 1. Install Java JDK (includes keytool)"
echo " 2. Ensure keytool is in your PATH"
echo " 3. Set JAVA_HOME environment variable"
exit 1
fi
else
echo "✓ keytool found: $(command -v keytool)"
fi
# Test keytool functionality
if ! keytool -help >/dev/null 2>&1; then
echo "Error: keytool is not functioning properly"
echo "Please check your Java installation"
exit 1
fi
# Check JAVA_HOME (recommended for consistency)
if [ -z "$JAVA_HOME" ]; then
echo "Info: JAVA_HOME is not set (recommended but not required)"
JAVA_PATH=$(command -v java)
POSSIBLE_JAVA_HOME=$(dirname "$(dirname "$JAVA_PATH")")
echo " Suggested JAVA_HOME: $POSSIBLE_JAVA_HOME"
else
echo "✓ JAVA_HOME: $JAVA_HOME"
fi
echo "✓ Java Runtime Environment validation passed"
echo
}
# Function to extract hostname and port from URL
parse_url() {
local url="$1"
# Remove protocol if present
url=$(echo "$url" | sed -e 's|^https://||' -e 's|^http://||' -e 's|^ssl://||')
# Extract hostname and port
if [[ "$url" == *":"* ]]; then
hostname=$(echo "$url" | cut -d':' -f1)
port=$(echo "$url" | cut -d':' -f2 | cut -d'/' -f1)
else
hostname=$(echo "$url" | cut -d'/' -f1)
port=443
fi
echo "$hostname:$port"
}
# Check if URL parameter is provided
if [ $# -eq 0 ]; then
echo "Error: URL parameter is required"
usage
fi
# Validate Java installation
check_java
URL="$1"
PARSED_URL=$(parse_url "$URL")
HOSTNAME=$(echo "$PARSED_URL" | cut -d':' -f1)
PORT=$(echo "$PARSED_URL" | cut -d':' -f2)
echo "Fetching SSL certificate chain from: $HOSTNAME:$PORT"
# Create temporary directory for certificates
TEMP_DIR=$(mktemp -d)
CERT_CHAIN_FILE="$TEMP_DIR/cert_chain.pem"
CERT_PEM_FILE="$TEMP_DIR/certificate.pem"
OUTPUT_P12_FILE="${HOSTNAME}_keystore.p12"
# Cleanup function
cleanup() {
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
echo "Retrieving certificate chain..."
# Get the certificate chain using openssl
if ! openssl s_client -connect "$HOSTNAME:$PORT" -servername "$HOSTNAME" -showcerts </dev/null 2>/dev/null | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > "$CERT_CHAIN_FILE"; then
echo "Error: Failed to retrieve certificate chain from $HOSTNAME:$PORT"
echo "Please check if the hostname and port are correct and accessible."
exit 1
fi
# Check if we got any certificates
if [ ! -s "$CERT_CHAIN_FILE" ]; then
echo "Error: No certificates found for $HOSTNAME:$PORT"
echo "Please verify the hostname and port are correct."
exit 1
fi
# Count the number of certificates in the chain
CERT_COUNT=$(grep -c -- "-----BEGIN CERTIFICATE-----" "$CERT_CHAIN_FILE" || echo "0")
echo "Found $CERT_COUNT certificate(s) in the chain"
# Extract just the server certificate (first one) for the keystore
sed -n '1,/-----END CERTIFICATE-----/p' "$CERT_CHAIN_FILE" > "$CERT_PEM_FILE"
echo "Certificate chain saved to temporary file: $CERT_CHAIN_FILE"
echo "Server certificate extracted to: $CERT_PEM_FILE"
# Display certificate information
echo
echo "Certificate Information:"
echo "========================"
openssl x509 -in "$CERT_PEM_FILE" -text -noout | grep -E "(Subject:|Issuer:|Not Before:|Not After:)" || echo "Could not extract certificate information"
echo
echo "Creating PKCS12 keystore..."
echo "You will be prompted to enter a password for the keystore."
echo "Note: Since we only have the public certificate (not the private key),"
echo "this keystore will contain the certificate for trust purposes only."
# Create PKCS12 keystore using keytool
# Note: We're creating a truststore since we don't have the private key
if keytool -importcert -file "$CERT_PEM_FILE" -alias "$HOSTNAME" -keystore "$OUTPUT_P12_FILE" -storetype PKCS12; then
echo
echo "SUCCESS: PKCS12 keystore created successfully!"
echo "Output file: $OUTPUT_P12_FILE"
echo
echo "You can view the keystore contents with:"
echo "keytool -list -keystore $OUTPUT_P12_FILE -storetype PKCS12"
else
echo "Error: Failed to create PKCS12 keystore"
exit 1
fi
echo
echo "Full certificate chain has been saved and processed."
echo "The keystore '$OUTPUT_P12_FILE' contains the server certificate for $HOSTNAME."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment