Creating an IBM HTTP Server key db from a .pfx file
It’s a question that I get quite often. “Can you create a IHS key database for me from this pfx certificate”? Multiple of our customers use IBM HTTP Server. Either for HCL Connections, but also as a reverse proxy for other services. Most of those customers use a wildcard certificate for their IHS server that has to be renewed each year. As I hate this kind of repetitive work, I created a script to do it for me. As it could be of use to others, I decided to create a blog article about it.
The script
So without further ado, here’s the script, which I have called create_keystore.sh
#!/bin/bash
# Enable error handling and debugging
set -e # Exit immediately if a command exits with a non-zero status
set -u # Treat unset variables as an error
set -o pipefail # Catch errors in piped commands
# Debugging mode: Uncomment the next line for verbose output
# set -x # Enable script debugging (prints each command before execution)
version=1.3
#################
# let's define some variables
# Default and can be set from the command line
PFXFILE=<default_path_and_filename of your>.pfx
PFXPW='<default_pfx_password>'
KDBFILE=<default_path_and_filename_of_your>.kdb
KDBPW='<default_kdb_password>'
CERT_LABEL="<label_of_your_certificate>"
# Should be set here
PATHTOGSKCAPI='/opt/IBM/HTTPServer/bin'
#################
# Intermediary files
P12FILE=wildcard-cert.p12
PRIVKEY_ENCRYPTED="privkey.pem.encrypted"
PRIVKEY="privkey.pem"
CERT="cert.pem"
CA_CHAIN="ca-chain.pem"
FULLCHAIN="fullchain.pem"
# Log function for error and status messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# Function to display help/usage
show_help() {
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " -pfx <file> Path to the PFX file (default: $PFXFILE)"
echo " -pfxpw <password> Password for the PFX file (default: $PFXPW)"
echo " -kdb <file> Path to the keystore (.kdb) file (default: $KDBFILE)"
echo " -kdbpw <password> Password for the keystore (default: $KDBPW)"
echo " -label <label> Certificate label (default: $CERT_LABEL)"
echo " -h, --help Show this help message and exit"
}
# Parse command-line arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-pfx)
PFXFILE="$2"
shift 2
;;
-pfxpw)
PFXPW="$2"
shift 2
;;
-kdb)
KDBFILE="$2"
shift 2
;;
-kdbpw)
KDBPW="$2"
shift 2
;;
-label)
CERT_LABEL="$2"
shift 2
;;
-h|--help)
show_help
exit 0
;;
*)
log "ERROR: Unknown option '$1'"
show_help
exit 1
;;
esac
done
# Cleanup function to remove intermediary files
cleanup_files() {
log "Cleaning up intermediary files..."
rm -f "$PRIVKEY_ENCRYPTED" "$PRIVKEY" "$CERT" "$CA_CHAIN" "$FULLCHAIN" "$P12FILE" || {
log "WARNING: Failed to remove some intermediary files. Please check manually."
}
log "Intermediary files removed successfully."
}
create_p12() {
log "Creating PKCS12 (.p12) file..."
if [[ ! -f "$PFXFILE" ]]; then
log "ERROR: PFX file '$PFXFILE' not found."
exit 1
fi
openssl pkcs12 -in "$PFXFILE" -nocerts -out privkey.pem.encrypted -nodes -password pass:"$PFXPW" || {
log "ERROR: Failed to extract private key from PFX file."
exit 1
}
openssl pkcs12 -in "$PFXFILE" -clcerts -nokeys -out cert.pem -password pass:"$PFXPW" || {
log "ERROR: Failed to extract certificate from PFX file."
exit 1
}
openssl pkcs12 -in "$PFXFILE" -cacerts -nokeys -chain -out ca-chain.pem -password pass:"$PFXPW" || {
log "ERROR: Failed to extract CA chain from PFX file."
exit 1
}
openssl rsa -in privkey.pem.encrypted -out privkey.pem || {
log "ERROR: Failed to decrypt private key."
exit 1
}
cat cert.pem ca-chain.pem > fullchain.pem || {
log "ERROR: Failed to create fullchain.pem."
exit 1
}
openssl pkcs12 -export -out "$P12FILE" -in fullchain.pem -inkey privkey.pem -password pass:"password" || {
log "ERROR: Failed to create .p12 file."
exit 1
}
log "PKCS12 (.p12) file created successfully: $P12FILE"
}
# Create keystore
create_keystore() {
log "Creating keystore..."
# Check if keystore (.kdb) already exists
if [[ -f "$KDBFILE" ]]; then
log "Keystore file already exists: $KDBFILE. Skipping keystore creation."
else
log "Keystore file does not exist. Creating new keystore..."
/opt/IBM/HTTPServer/bin/gskcapicmd -keydb -create -db "$KDBFILE" -pw "$KDBPW" -stash || {
log "ERROR: Failed to create keystore."
exit 1
}
fi
# Import PKCS#12 file into keystore
if [[ ! -f "$P12FILE" ]]; then
log "ERROR: .p12 file '$P12FILE' not found. Ensure 'create_p12' function ran successfully."
exit 1
fi
log "Importing PKCS#12 (.p12) file into keystore..."
$PATHTOGSKCAPI/gskcapicmd -cert -import -db "$P12FILE" -pw "password" -target "$KDBFILE" -target_pw "$KDBPW" || {
log "ERROR: Failed to import certificate into keystore."
exit 1
}
# Set default certificate
log "Setting default certificate in keystore..."
$PATHTOGSKCAPI/gskcapicmd -cert -setdefault -label "$CERT_LABEL" -db "$KDBFILE" -stashed || {
log "ERROR: Failed to set default certificate in keystore."
exit 1
}
log "Keystore created successfully: $KDBFILE"
}
show_certs()
{
# and print the output
$PATHTOGSKCAPI/gskcapicmd -cert -list -db "$KDBFILE" -stashed
}
# Main script logic
log "Starting script version $version..."
create_p12
create_keystore
show_certs
# Cleanup intermediary files
cleanup_files
echo "Done. See new keystore at $KDBFILE"
gskcapicmd
Many people use ikeyman to create IHS key databases, but this can’t be used from a command line and needs a GUI installed, which is usually not there on the server. Luckily, there’s a program which does work from a command line: gskcapicmd. What I do in the script, is that I first create a key database and then add the certificates to it. Regretfully, gskcapicmd can’t handle the .pfx files that I tend to get with certificates to add (or maybe I need to add a switch that I so far haven’t discovered), so in the script, I first unpack the .pfx file to a private key, the server/wildcard certificate and the intermediary and root certificates and add them to a new .p12 keyfile that I can import with gskcapicmd. That’s the create_p12() function that you see in the script.
Optional input parameters
One parameter which you should define in the script is the location of your IHS binary directory. By default, this is /opt/IBM/HTTPServer/bin, but if you installed IHS somewhere else, you’ll have to change that in the script. All other parameters can both be set in the script or given along on the command line. You can see the parameters by using ./create_keystore.sh -h
.
Log and debugging
The script has extensive logging, so you can see what’s going wrong. You can even extend that logging, by uncommenting the set -x
line in the script.
Updating httpd.conf
The script creates a key database, but doesn’t update the httpd.conf, so if your key database has a different name than your currently active key database, you have to edit this file yourself and restart IHS.
Let me know if you have any questions or tips for improvement.