Attached is a bash script that I am developing to automate the generation of TLSA records from Letsencrypt certificates.

the script is called from the certbot renew hook, it can also be run stand alone - Certbot_TLSAgen path-to-certificate "space separated list of domains included in cert"

It seems to work, but would some kind sole take a look and where I have or are about to screw up.


Any suggestions as to how to get the output into my DNS (Bind9) preferably without using nsupdate. I am not keen on nsupdate as it makes a mess of the zone files, which I use as documentation for my DNS.


Has anybody heard of a electronic "one time pad" system.

TIA

JohnA





#!/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 <http://www.gnu.org/licenses/>.
#
#=====================================================================================================================

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

Reply via email to