#!/bin/bash


help() {
  cat << EOH

NAME
    $1 - check DANE TLSA resource records

SYNOPSIS
    $1 [-h HOST] [-p PORT]
    $1 [-c] HOST[:PORT]
    $1 -H

DESCRIPTION
    This script checks the DANE TLSA resource records of a given host.

OPTIONS
    -h HOST
        Host, to be checked. If HOST ist not given, 'wu6ch.de' is used as
        default.

    -p PORT
        Port of host, to be checked. If PORT ist not given, 443 is used as
        default.

    -c HOST:PORT
        It is also possible to set HOST and PORT (separated with ':') with one
        option. If this variant is used, it takes precedence over options 'h'
        and 'p'. Setting HOST:PORT without typing '-c' explicitly is also
        allowed.

    -H
        This "manual page".

EXIT STATUS
    If all DANE authentications succeed ("Verification: OK"), the script exits
    with 0, otherwise with a value unequal to 0.

EXAMPLE
    Check the DANE TLSA records of the host 'argon.wu6ch.de', port 25:
        $1 -h argon.wu6ch.de -p 25
        $1 -c argon.wu6ch.de:25
        $1 argon.wu6ch.de:25

    All variants give the same result:

        argon.wu6ch.de:25  3 1 1 0bcade22628155366833a466f03d7190bc87d1722201d1f449bbe31d76ef52e9

        Protocol version: TLSv1.3
        Ciphersuite: TLS_AES_256_GCM_SHA384
        Peer certificate: CN = argon.wu6ch.de
        Hash used: SHA256
        Signature type: RSA-PSS
        Verification: OK
        Verified peername: argon.wu6ch.de
        DANE TLSA 3 1 1 ...2201d1f449bbe31d76ef52e9 matched EE certificate at depth 0


        argon.wu6ch.de:25  2 1 1 8d02536c887482bc34ff54e41d2ba659bf85b341a0a20afadb5813dcfbcf286d

        Protocol version: TLSv1.3
        Ciphersuite: TLS_AES_256_GCM_SHA384
        Peer certificate: CN = argon.wu6ch.de
        Hash used: SHA256
        Signature type: RSA-PSS
        Verification: OK
        Verified peername: argon.wu6ch.de
        DANE TLSA 2 1 1 ...a0a20afadb5813dcfbcf286d matched TA certificate at depth 1

AUTHOR
    Wolfgang <w6g@wu6ch.de>

LICENSE
    MIT (https://wu6ch.de/bash/functional_bash/LICENSE)

SEE ALSO
    Functional Bash (https://wu6ch.de/bash/functional_bash/)
EOH
}


set_env() {
  source "/usr/local/lib/functional_bash.sh"

  declare -gr dig="dig"
  declare -gr openssl="openssl"

  local default_host="wu6ch.de" default_port="443"

  # shellcheck disable=SC2034
  local -A options=()
  local -a remaining_args=()

  get_options "h:p:c:" options remaining_args help "$@" && {
    host="$(get_arg options "h" "$default_host")"
    port="$(get_arg options "p" "$default_port")"

    set -- "${remaining_args[@]}"
    local connection ; connection="$(get_arg options "c" "${1-"$(get_unset)"}")"

    is_set "$connection" && {
      host="$(cut -d ":" -f 1 <<< "$connection")"
      port="$(cut -d ":" -f 2 <<< "$connection")"
      { [ -z "$port" ] || [ "$port" == "$host" ]; } && port="$default_port"
    }

    declare -gr host port
  }
}


read_tlsa() {
  # $1: host
  # $2: port

  "$dig" +short +nosplit "_${2}._tcp.${1}" TLSA | tr '[:upper:]' '[:lower:]' | sort -r
}


filter_output() {
  local not_wanted=(
    "^CONNECTION ESTABLISHED"
    "^Requested Signature Algorithms"
    "CHUNKING"
    "^Server Temp Key"
    "^DONE"
  )

  local gr_opts=()
  to_array gr_opts "$(list "${not_wanted[@]}" | lbind printf -- '-e\n%s\n')"
  grep -v "${gr_opts[@]}"
}


check_dane_authentication() {
  # $1: TLSA RR data

  echo
  echo "$host:$port  $1"
  echo

  local msg="" opts=() diag_output

  [ "$port" == "25" ] && { msg="QUIT"; opts=( "-starttls" "smtp" ); }

  diag_output="$(echo "$msg" \
                    | "$openssl" s_client \
                          -crlf \
                          -brief \
                          -host "$host" \
                          -port "$port" \
                          "${opts[@]}" \
                          -dane_tlsa_domain "$host" \
                          -dane_tlsa_rrdata "$1" 2>&1 \
                    | filter_output)"

  echo "$diag_output"
  echo

  grep -q "\<Verification: OK\>" <<< "$diag_output"
}


set_env "$@" \
  && are_installed "$dig" "$openssl" \
  && read_tlsa "$host" "$port" | lbind check_dane_authentication


# EOF - vim:cc=101
