#!/bin/sh -e
# Check if the script is being sourced or not.
[ "$_" != "$0" ] && expr "$-" : ".*i.*" > /dev/null && sourced=1


# Returns the subject hash of the certificate path provided.
alias subject_hash='openssl x509 -noout -subject_hash -in'

# Returns the issuer hash of the certificate path provided.
alias issuer_hash='openssl x509 -noout -issuer_hash -in'

find_root_cert () {
    # Returns the (first) root (self-signed) certificate found in the list
    # of file paths provided.
    for filename in "$@"
    do
        if [ -f "$filename" ] && \
            [ "$(subject_hash $filename)" = "$(issuer_hash $filename)" ]
        then
            echo "$filename"
            break
        fi
    done
}

find_cert_by_hash () {
    # Recieves the issuer hash and a list of file paths, returns the path to
    # the certificate which was issued by that hash.
    certhash="$1"
    shift
    for filename in "$@"
    do
        if [ -f "$filename" ] && \
            [ "$(issuer_hash $filename)" = "$certhash" ] && \
            [ "$(issuer_hash $filename)" != "$(subject_hash $filename)" ]
        then
            echo "$filename"
            break
        fi
    done
}

unbundle_cert () {
    # Recieves a file path, creates a directory named certs with all of the
    # individual certs contained within that file inside the directory (the
    # filenames are the subject hash for each certificate).
    mkdir -p certs
    awk '/-----BEGIN[A-Z0-9 ]*CERTIFICATE-----/ {n++} \
        n > 0 {print > "certs/cert" (1+n)}' "$1"
    for certificate in certs/cert*
    do
        [ -f "$certificate" ] || continue
        mv "$certificate" "certs/$(subject_hash $certificate)"
    done
}

bundle_certs () {
    for filename in "$@"
    do
        [ -f "$filename" ] && unbundle_cert "$filename"
    done
    cd certs
    issuer="$(find_root_cert *)"
    if [ -z "$issuer" ]
    then
        echo "Failed to find root certificate." > /dev/stderr
        exit 1
    fi
    issued="$(find_cert_by_hash $issuer *)"
    while [ -n "$issued" ]
    do
        ordered_certs="$issued $ordered_certs"
        issuer="$issued"
        issued="$(find_cert_by_hash $issuer *)"
    done
    cat $ordered_certs
    cd ..
    rm -r certs
}


if [ ! "$sourced" ] && [ $# -eq 0 ]
then
    echo "Usage: $0 filename [filename2 [filename3 ...]]" > /dev/stderr
    exit 1
fi
[ ! "$sourced" ] && bundle_certs "$@"
