#!/bin/sh
set -e

# For backwards compatibility reasons, future versions of this script must
# support the syntax "update-ca-trust extract" trigger the generation of output
# files in $DEST.

ETCDIR=/etc
DEST=$ETCDIR/ca-certificates/extracted

# Prevent p11-kit from reading user configuration files.
export P11_KIT_NO_USER_CONFIG=1

usage() {
    fold -s -w 79 >&2 <<EOF
Usage: $0 [extract] [-o DIR|--output=DIR]

Update the system trust store in $DEST.

COMMANDS
  (absent/empty command): Same as the extract command described below.

  extract: Instruct update-ca-trust to scan the source configuration in
  /usr/share/ca-certificates/trust-source and /etc/ca-certificates/trust-source
  and produce updated versions of the consolidated configuration files stored
  below the $DEST directory hierarchy.

EXTRACT OPTIONS
  -o DIR, --output=DIR: Write the extracted trust store into the given
                        directory instead of updating
                        $DEST.
  --init:               Only update trust store if it doesn't exist yet
EOF
}

extract() {
    dest="$DEST"
    init=0

    # can't use getopt here. ca-certificates can't depend on a lot
    # of other libraries since openssl depends on ca-certificates
    # just fail when we hand parse

    while [ "$#" -ne 0 ]; do
        case "$1" in
            "--init")
                init=true
                shift
                continue
                ;;
            "-o"|"--output")
                dest="$2"
                shift 2
                continue
                ;;
            "--")
                shift
                break
                ;;
            *)
                usage
                exit 1
                ;;
        esac
    done

    if [ -d "$dest" ] && [ $init = "true" ]; then
        echo "Not updating in init mode when $dest already exists."
        return 0
    fi

    rm -r "$dest" || true
    mkdir -p "$dest"

    # Create etc/ssl/certs if not there yet
    if ! [ -d "$ETCDIR/ssl/certs/java" ]; then
        mkdir -p "$ETCDIR"/ssl/certs/java
    fi

    # Simple PEM bundles (BEGIN CERTIFICATE)
    trust extract --overwrite --comment --format=pem-bundle --filter=ca-anchors \
          --purpose=server-auth "$dest/tls-ca-bundle.pem"
    trust extract --overwrite --comment --format=pem-bundle --filter=ca-anchors \
          --purpose=email "$dest/email-ca-bundle.pem"
    trust extract --overwrite --comment --format=pem-bundle --filter=ca-anchors \
          --purpose=code-signing "$dest/objsign-ca-bundle.pem"

    # OpenSSL PEM bundle that includes trust flags (BEGIN TRUSTED CERTIFICATE)
    trust extract --overwrite --comment --format=openssl-bundle \
          --filter=certificates "$dest/ca-bundle.trust.crt"

    # TianoCore EDK II bundle
    trust extract --overwrite --format=edk2-cacerts --filter=ca-anchors \
          --purpose=server-auth "$dest/edk2-cacerts.bin"

    # Java KeyStore bundle
    trust extract --overwrite --format=java-cacerts --filter=ca-anchors \
          --purpose=server-auth "$dest/java-cacerts.jks"

    # Hashed directory of simple PEM certs
    # (BEGIN CERTIFICATE, usable as OpenSSL CApath and by GnuTLS)
    trust extract --overwrite --format=pem-directory-hash --filter=ca-anchors \
          --purpose=server-auth "$dest/cadir"

    if [ "$dest" = "$DEST" ]; then
        # We can't extract directly to /etc/ssl/certs as this would indiscriminately
        # empty the directory, but it contains packaged symlinks and directories.

        # Symlink all files from the extracted cadir
        for f in "$dest"/cadir/*; do
            ln -fs "$f" $ETCDIR/ssl/certs/
        done

        # Now find and remove all broken symlinks
        find -L $ETCDIR/ssl/certs -maxdepth 1 -type l -delete

        # Java
        ln -fs "$dest/java-cacerts.jks" $ETCDIR/ssl/certs/java/cacerts
        # Compatibility link for OpenSSL using /etc/ssl as CAdir
        # Used in preference to the individual links in /etc/ssl/certs
        ln -fs "$dest/tls-ca-bundle.pem" "$ETCDIR/ssl/cert.pem"
        # Compatibility link for legacy bundle (Debian)
        ln -fs "$dest/tls-ca-bundle.pem" "$ETCDIR/ssl/certs/ca-certificates.crt"
        # Compatibility link for legacy bundle (RHEL/Fedora)
        ln -fs "$dest/tls-ca-bundle.pem" "$ETCDIR/ssl/certs/ca-bundle.crt"
    fi
}

if [ "$#" -le 1 ]; then
    set -- extract
fi

case "$1" in
    "extract")
        shift
        extract "$@"
        ;;
    "--"*|"-"*)
        # First parameter seems to be an option, assume the command is 'extract'
        extract "$@"
        ;;
    *)
        echo >&2 "Error: Unknown command: $1"
        echo >&2
        usage
        exit 1
        ;;
esac

# vim:set sw=2 sts=-1 et:
