Files @ 61750d5ab4b2
Branch filter:

Location: majic-scripts/x509/crlpublisher.sh

branko
Added the CRL publisher script that can be used with EJBCA, and the notifier about uncommitted changes for etckeeper.
#!/bin/bash
#
# crlpublisher.sh
#
# Copyright (C) 2012, Branko Majic <branko@majic.rs>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

program="crlpublisher.sh"
version="0.1.1"

function usage() {
    cat <<EOF
$program $version, a non-interactive utility for publishing CRL's.

Usage: $program [OPTIONS] crl_file

$program is a non-interactive utility for publishing CRL's. It takes a single
argument pointing to the CRL file which should be published. The CRL file should
be provided either in DER or PEM encoding.

The script is written to support several types of publishers. Currently
supported publishers are:

    - scp - Publishes to a remote server using public-key authentication through
      SSH's scp command.

Publishing options are kept within configuration files. Configuration files
should be placed in one of the following directories:

    - /etc/crlpublisher/
    - ~/.crlpublisher/

Configuration files must end with a .conf extension. All other files will be
ignored. Each configuraiton file should contain information for a single
publisher matching a single issuer DN.

Common configuration options

    issuerDn (mandatory) - Specifies the distinguished name of the issuer of CRL
    which should be matched for the particular configuration.

    publisher (mandatory) - Type of publisher this configuration refers to.


Configuration options for 'scp' publisher:

    remoteHost (mandatory) - Remote IP or resolvable hostname/FQDN of the target
    server to which the CRL will be published.
    
    remoteLocation (mandatory) - Full path on the remote server to the directory
    location to which the CRL will be published.

    remoteUser (optional) - Name of the remote user which will be used for
    logging-in. Default is the user executing the script.

    privateKey (optional) - Path to the private key which should be used for
    logging-in onto remote server. Default is ~/.ssh/id_rsa.

    remotePort (optional) - Remote port that should be used for connecting to
    the SSH server on remote host. Default is to use port 22.


$program accepts the following options:

    -v        show script version and licensing information
    -h        show usage help


Please report bugs and send feature requests to <branko@majic.rs>.
EOF
}

function version() {
        cat <<EOF
$program, version $version

+-----------------------------------------------------------------------+
| Copyright (C) 2012, Branko Majic <branko@majic.rs>                    |
|                                                                       |
| This program is free software: you can redistribute it and/or modify  |
| it under the terms of the GNU General Public License as published by  |
| the Free Software Foundation, either version 3 of the License, or     |
| (at your option) any later version.                                   |
|                                                                       |
| This program is distributed in the hope that it will be useful,       |
| but WITHOUT ANY WARRANTY; without even the implied warranty of        |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
| GNU General Public License for more details.                          |
|                                                                       |
| You should have received a copy of the GNU General Public License     |
| along with this program.  If not, see <http://www.gnu.org/licenses/>. |
+-----------------------------------------------------------------------+

EOF
}

#
# Helper function that parses a CRL.
#
# Sets:
#     crlIssuerDn - to the value of the CRL issuer's distinguished name.
#
function readCrlInfo() {
    local crlFile="$1"
    unset crlIssuerDn

    # Assume that the CRL is in DER format
    if ! crlIssuerDn="$(openssl crl -issuer -inform DER -noout -in "$crlFile")"; then
        if ! crlIssuerDn="$(openssl crl -issuer -inform PEM -noout -in "$crlFile")"; then
            echo "Invalid CRL file '$crlFile'" >&2
            return 1
        fi
    fi

    crlIssuerDn="$(echo "$crlIssuerDn" | sed -e 's#^issuer=/##;s#/#,#g')"

    return 0
}

#
# Helper function for clearing the common parameters. This function output
# commands that should be executed in order to clear the parameters (by using
# the "echo" command for example).
#
function clearCommonParameters() {
    echo "local issuerDn publisher"
}

#
# Helper function for verifying the common parameters
#
function verifyCommonParameters() {
    if [[ -z "$issuerDn" ]]; then
        echo "Publisher ($configFile): missing issuer DN" >&2
        return 1
    fi
    if [[ -z "$publisher" ]]; then
        echo "Publisher ($configFile): missing publisher type." >&2
        return 1
    fi
}

#
# Implementation of scp-based publisher.
#
function publish_through_scp() {
    local configFile="$1" crlFile="$2"
    local remoteUser="$USER" remoteHost remoteLocation privateKey="$HOME/.ssh/id_rsa" remotePort="22"

    $(clearCommonParameters)

    . "$configFile"

    verifyCommonParameters || return 1

    if ! [[ -f $privateKey ]]; then
        echo "SCP publisher ($configFile): invalid private key - '$privateKey'." >&2
        return 1
    elif [[ -z $remoteHost ]]; then
        echo "SCP publisher ($configFile): missing 'remoteHost' option." >&2
        return 1
    elif [[ -z $remoteLocation ]]; then
        echo "SCP publisher ($configFile): missing 'remoteLocation' option." >&2
        return 1
    elif [[ -z "$remotePort" ]]; then
        echo "SCP publisher ($configFile): missing 'remotePort' option." >&2
        return 1
    elif [[ ! $remotePort =~ ^[[:digit:]]+$ ]]; then
        echo "SCP publisher ($configFile): invalid remote port - '$remotePort'." >&2
        return 1
    fi

    if [[ $issuerDn == $crlIssuerDn ]]; then
        if ! scp -P "$remotePort" -i "$privateKey" "$crlFile" "$remoteUser"@"$remoteHost":"$remoteLocation"; then
            echo "SCP publisher ($configFile): failed to publish CRL for '$crlIssuerDn'." >&2
	    return 2
        fi
    fi
}

# If no arguments were given, just show usage help.
if [[ -z $1 ]]; then
    usage
    exit 0
fi

# Parse the arguments
while getopts "vh" opt; do
    case "$opt" in
        v) version
           exit 0;;
        h) usage
           exit 0;;
        *) usage
           exit 1;;
    esac
done
i=$OPTIND
shift $(($i-1))

# Determine the configuration directory to be used
configDir="/etc/crlpublisher"

[[ ! -d $configDir ]] && configDir="$HOME/.crlpublisher"

if [[ ! -d $configDir ]]; then
    cat <<EOF >&2
No configuration directory could be found. Please create configuration directory
and the necessary configuration files in one of the following locations:

- /etc/crlpublisher/
- $HOME/crlpublisher/
EOF
    exit 2
fi

# The first argument should be a CRL file
crlFile="$1"

# Obtain the issuer's DN first
readCrlInfo "$crlFile" || exit $?

# Assume that the operation suceeds unless the publisher fails for any reason.
operationResult=0

# Process each configuration file
while read configFile; do
    unset publisher
    eval "$(grep "^publisher=" "$configFile")"
    # Execute operation and if it failed, that's the status the script will
    # return.
    "publish_through_$publisher" "$configFile" "$crlFile" || operationResult="$?"
done < <(find "$configDir" -name "*.conf")

exit "$operationResult"