#!/bin/bash #===================================================================================================================== # # Copyright (c) 2017 John L. Allen # # 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 . # #===================================================================================================================== declare -a TLSA_Services=( smtp imap submission sieve dav davical https ) # An arrrayof services for which TLSA might be needed # these two variables are ???? Certbot_Lineage= # path to the certbot generated cert ...(RENEWED_LINEAGE or $1) declare -a Certbot_Domains # An array into which RENEWED_DOMAINS or $2 Domains are split # default values #TLSA_File_Path="/etc/bind/tlsa/" # where do you want to put the TLSA records, default values TLSA_File_Path="./tlsa_test/" # where do you want to put the TLSA records, default values - during testing TLSA_Filename_Base="tlsa" # base filename for the TLSA records - generated as base_filename.sequence_number TLSA_TTL=3600 # TLSA DNS record TTL TLSA_Usage=3 # TLSA usage TLSA_Selector=1 # TLSA selector TLSA_Type=1 # TLSA type # #===================================================================================================================== #===================Message output function - will need changing to output multi language message===================== function error_message() { echo $1 1>&2 exit 1 } #===================================================================================================================== #================ Check of either the Certbot set environment variables or the command line paramater================= #================ depending upon how this script is invocked ================= #===================================================================================================================== function Check_Env_Variables() { # Has command line parameter 1 or the environment variable RENEWED_LINEAGE been set. # The Command line parameter overides the environment variable [[ -z $RENEWED_LINEAGE ]] && Certbot_Lineage=$1 || Certbot_Lineage=$RENEWED_LINEAGE if [[ -z $Certbot_Lineage ]]; then error_code= $(error_message "Command line parameter 1 or the evironment variable \"RENEWED_LINEAGE\" was not set, exiting") elif ! [[ -d $Certbot_Lineage ]]; then error_code= $(error_message "Command line parameter 1 or the evironment variable \"RENEWED_LINEAGE\" is not a directory, exiting") fi # Has command line parameter 2 or the environment variable RENEWED_DOMAINS been set. # The Command line parameter overides the environment variable # If more than one domain is specified they are expected to be in the form of a space seperated list [[ -z $RENEWED_DOMAINS ]] && Certbot_Domains=( $2 ) || Certbot_Domains=( ${RENEWED_DOMAINS} ) if [[ ${#Certbot_Domains[@]} -le 0 ]]; then error_code=$(error_message "Command line parameter 2 or the evironment variable \"RENEWED_DOMAINS\" was not set, exiting") fi # Check that the TLSA_File_Path is the location (directory) where files containing the generated TLSA records will be put # if ! [ -d $TLSA_File_Path ]; then error_code=$(error_message "the directory $TLSA_File_Path does not exist, please specify where the generated records are to be stored") fi # Check that the TLSA filename base has been set. # The filename base is used to generate actual filenames in the form of base.sequence # if [ -z "$TLSA_Filename_Base" ]; then error_code=$(error_message "Please specify a base filename into which the generated TLSA records can be placed") fi return $error_code } #===================================================================================================================== #=======Set the output file name, including path. #=======The filename is derived from TLSA_Filename_Base plus a generated serial number suffix zzz=" " function Set_Output_Destination() { count=$( ls -1 $1 | wc -l ) name=$(printf "%s%s.%04d" "$1" "$2" "$count") while [ -a $name ]; do count=$(( $count+1)) name=$(printf "%s%s.%04d" "$1" "$2" "$count") done echo $name } #===================================================================================================================== #******************************************************************************************************************** #******************************************************************************************************************** # THe following functions were stolen from Viktor Dukhovni's tlsagen #******************************************************************************************************************** #******************************************************************************************************************** #===================================================================================================================== extract() { case "$1" in 0) openssl x509 -in "$2" -outform DER;; 1) openssl x509 -in "$2" -noout -pubkey | openssl pkey -pubin -outform DER;; esac } digest() { case "$1" in 0) cat;; 1) openssl dgst -sha256 -binary;; 2) openssl dgst -sha512 -binary;; esac } Set_TLSA_Usage() { case "$(echo $1 | tr '[A-Z]' '[a-z]')" in 0|pkix-[ct]a) TLSA_usage=0;; 1|pkix-ee) TLSA_usage=1;; 2|dane-[ct]a) TLSA_usage=2;; 3|dane-ee) TLSA_usage=3;; *) error "Invalid certificate usage: $1";; esac } Set_TLSA_Selector() { case "$(echo $1 | tr '[A-Z]' '[a-z]')" in 0|cert) TLSA_selector=0;; 1|spki|pkey) TLSA_selector=1;; *) error "Invalid selector: $1";; esac } Set_TLSA_Type() { case "$(echo $1 | tr '[A-Z]' '[a-z]')" in 0|full) TLSA_Type=0;; 1|sha2-256|sha256|sha-256) TLSA_Type=1;; 2|sha2-512|sha512|sha-512) TLSA_Type=2;; *) error "Invalid matching type: $1";; esac } #===================================================================================================================== #===================================================================================================================== # as we cannot pass and parameters when this is called from the certbot renew hooks # we will have to put them somewhere else, # Defailt for general parameters # if [ -f /etc/default/Cerbot_TLSAgen.cf ]; then . /etc/default/Cerbot_TLSAgen.cf; fi Check_Env_Variables "$1" "$2" # If we are running as a command then these two should be set, if not certbot environment variables should be [[ $? != 0 ]] && exit # ooops! exit. this needs some improvement #******needs testing # Certbot_Lineage should now be set, so pick up any cert based paramamters from the ".../live/certname" directory # if [ -f ${Certbot_Lineage}Certbot_TLSAgen.cf ]; then . ${Certbot_Lineage}Certbot_TLSAgen.cf; fi TLSA_Record_Store=$(Set_Output_Destination $TLSA_File_Path $TLSA_Filename_Base) # generate the output file location Path + generate filename [[ $? != 0 ]] && exit # ooops! exit. this needs some improvement TLSA_Digest=$( extract $TLSA_Selector ${Certbot_Lineage}cert.pem | digest $TLSA_Type | od -vAn -tx1 | tr -d ' \012' # Generate the TLSA key as a HEX string. As we are dealiing with a single cert do this once exit $(( ${PIPESTATUS[0]} | ${PIPESTATUS[1]} | ${PIPESTATUS[2]} )) ) [[ $? != 0 ]] && exit # ooops! exit. this needs some improvement # for each (sub)domain listed, check to see if it is a service doamin that we might like to have a TLSA record for # for domain in $( seq 0 $((${#Certbot_Domains[@]} -1 )) ); do TLSA_target=${Certbot_Domains[domain]%.} # I am not sure whether the Cerbot list of (sub)domains has a trailing "." TLSA_domain=${TLSA_target#*.} # Hopefully this will strip off the sub-domain part giving me a domain-name + TLD if [[ -z "${TLSA_domain##*.*}" ]]; then # Primitive test - if there is a "." this is likely to be domin + TLD for service in $( seq 0 $((${#TLSA_Services[@]} -1 )) ); do # Do this for each of the services that might us a TLSA record while read srv_priority srv_weight srv_port srv_host; # read the out put of a DIG for a SRV record do if [ ${srv_host%.} == $TLSA_target ]; then # if the host returned by dig = the Cerbot target output a TLSA record printf "_%d._tcp.%s %d IN TLSA %d %d %d %s\n"\ "$srv_port" "$srv_host" "$TLSA_TTL" "$TLSA_Usage" "$TLSA_Selector" "$TLSA_Type" "$TLSA_Digest" >> $TLSA_Record_Store fi done < <(dig SRV _${TLSA_Services[$service]}._tcp.${TLSA_domain} +short) # done # SOA_domain=$TLSA_domain # read soa_ns soa_admin soa_seq soa_t1 soa_t2 soa_t3 soa_t4 < <(dig SOA $SOA_domain +short) fi done