DST_TMP_FULLCHAIN="$DST_TMP_PATH/fullchain.pem"
DST_TMP_SERVER="$DST_TMP_PATH/server.pem"
PATH="$PATH:/usr/local/bin"
+SECRET_FILE=".secret"
# Copy Certificate
# Copy Certificate in $dst folder
USER="fritz5738"
ALIVE=$(ping -c 1 $HOST |grep ttl)
if [ ! -z "$ALIVE" ]; then
- update_certificate_fritz $HOST $USER $SRC_FULLCHAIN $SRC_KEY
+ if [ -f "$SECRET_FILE" ]; then
+ password=$(awk -F':' -v host="$HOST" '$1 == host {print $2}' "$SECRET_FILE")
+ update_certificate_fritz -b $HOST -u $USER -p $password -c $SRC_FULLCHAIN -k $SRC_KEY
+ else
+ echo "$SECRET_FILE not found"
+ fi
else
echo "Host $HOST not alive, skipped"
fi
USER="fritz9145"
ALIVE=$(ping -c 1 $HOST |grep ttl)
if [ ! -z "$ALIVE" ]; then
- update_certificate_fritz $HOST $USER $SRC_FULLCHAIN $SRC_KEY
+ if [ -f "$SECRET_FILE" ]; then
+ password=$(awk -F':' -v host="$HOST" '$1 == host {print $2}' "$SECRET_FILE")
+ update_certificate_fritz -b $HOST -u $USER -p $password -c $SRC_FULLCHAIN -k $SRC_KEY
+ else
+ echo "$SECRET_FILE not found"
+ fi
else
echo "Host $HOST not alive, skipped"
fi
#!/bin/bash
# Parameters
-PASSWORD=""
-
-# check inputs:
-if [ $# -eq 0 ]; then
- echo "Wrong parameters. Please use:"
- echo "- host"
- echo "- username"
- echo "- certificate"
- echo "- key"
- exit
+CURL_CMD="curl"
+ICONV_CMD="iconv"
+OPENSSL_CMD="openssl"
+
+SUCCESS_MESSAGES="^ *(Das SSL-Zertifikat wurde erfolgreich importiert|Import of the SSL certificate was successful|El certificado SSL se ha importado correctamente|Le certificat SSL a été importé|Il certificato SSL è stato importato|Import certyfikatu SSL został pomyślnie zakończony)"
+
+DEBUG_OUTPUT=/tmp/fritzbox.debug
+
+function usage {
+ echo "Usage: $0 [-b baseurl] [-u username] [-p password] [-c fullchain certificate] [-k privkey]" >&2
+ exit 64
+}
+
+function error {
+ local msg=$1
+
+ [ "${msg}" ] && echo "${msg}" >&2
+ exit 1
+}
+
+md5cmd=
+
+for cmd in md5 md5sum; do
+ if which "${cmd}" >/dev/null 2>&1; then
+ md5cmd=${cmd}
+ break
+ fi
+done
+
+if [ -z "${md5cmd}" ]; then
+ error "Missing command for calculating MD5 hash"
+fi
+
+exit=0
+
+for cmd in ${CURL_CMD} ${ICONV_CMD} ${OPENSSL_CMD}; do
+ if ! which "${cmd}" >/dev/null 2>&1; then
+ error "Please install ${cmd}" >&2
+ fi
+done
+
+[ ${exit} -ne 0 ] && exit ${exit}
+
+while getopts ":b:p:u:c:k:dh" opt; do
+ case ${opt} in
+ b)
+ baseurl=$OPTARG
+ ;;
+ p)
+ password=$OPTARG
+ ;;
+ u)
+ username=$OPTARG
+ ;;
+ c)
+ fullchain=$OPTARG
+ ;;
+ k)
+ privkey=$OPTARG
+ ;;
+ d)
+ debug="true"
+ ;;
+ h)
+ usage
+ ;;
+ \?)
+ echo "Invalid option: $OPTARG" >&2
+ echo >&2
+ usage
+ ;;
+ :)
+ echo "Invalid option: $OPTARG requires an argument" >&2
+ echo >&2
+ usage
+ ;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+exit=0
+
+# strip trailing slash
+baseurl="${baseurl%/}"
+
+if [ ! -r "${fullchain}" ] || [ ! -r "${privkey}" ]; then
+ error "Certpath ${certpath} must contain fullchain.pem and privkey.pem"
fi
-# save inputs
-HOST=$1
-USERNAME=$2
-CERT=$3
-KEY=$4
+if ! ${OPENSSL_CMD} rsa -in "${privkey}" -check -noout &>/dev/null; then
+ error "FRITZ!OS only supports RSA private keys."
+fi
+
+if [ -n "${debug}" ]; then
+ curl_opts="-v -s --stderr -"
+
+ function process_curl_output {
+ grep -v '^[*{}]' | sed -e '1i\
+' | tee -a ${DEBUG_OUTPUT}
+ }
-# make and secure a temporary file
-TMP="$(mktemp -t XXXXXX)"
-chmod 600 $TMP
+ echo "Debug output will be written to ${DEBUG_OUTPUT}"
+else
+ curl_opts="-sS"
+
+ function process_curl_output {
+ cat
+ }
+fi
+
+request_file="$(mktemp -t XXXXXX)"
+trap 'rm -f "${request_file}"' EXIT
+
+echo "----------------------------------------------------------------" >>${DEBUG_OUTPUT}
+date >>${DEBUG_OUTPUT}
# login to the box and get a valid SID
-CHALLENGE=`wget -q -O - $HOST/login_sid.lua | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//'`
-HASH="`echo -n $CHALLENGE-$PASSWORD | iconv -f ASCII -t UTF16LE |md5sum|awk '{print $1}'`"
-SID=`wget -q -O - "$HOST/login_sid.lua?sid=0000000000000000&username=$USERNAME&response=$CHALLENGE-$HASH"| sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//'`
+# shellcheck disable=SC2086
+challenge="$(${CURL_CMD} ${curl_opts} "${baseurl}/login_sid.lua" | process_curl_output | sed -ne 's/^.*<Challenge>\([0-9a-f][0-9a-f]*\)<\/Challenge>.*$/\1/p')"
+if [ -z "${challenge}" ]; then
+ error "Invalid challenge received."
+fi
+
+md5hash="$(echo -n "${challenge}-${password}" | ${ICONV_CMD} -f ASCII -t UTF-16LE | ${md5cmd} | awk '{print $1}')"
+
+# shellcheck disable=SC2086
+sid="$(${CURL_CMD} ${curl_opts} "${baseurl}/login_sid.lua?username=${username}&response=${challenge}-${md5hash}" | process_curl_output | sed -ne 's/^.*<SID>\([0-9a-f][0-9a-f]*\)<\/SID>.*$/\1/p')"
+if [ -z "${sid}" ] || [ "${sid}" = "0000000000000000" ]; then
+ error "Login failed."
+fi
+
+certbundle=$(cat "${fullchain}" "${privkey}" | grep -v '^$')
# generate our upload request
-BOUNDARY="---------------------------"`date +%Y%m%d%H%M%S`
-printf -- "--$BOUNDARY\r\n" >> $TMP
-printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n$SID\r\n" >> $TMP
-#printf -- "--$BOUNDARY\r\n" >> $TMP
-#printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n$CERT_PASSWORD\r\n" >> $TMP
-printf -- "--$BOUNDARY\r\n" >> $TMP
-printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> $TMP
-printf "Content-Type: application/octet-stream\r\n\r\n" >> $TMP
-cat $KEY >> $TMP
-cat $CERT >> $TMP
-printf "\r\n" >> $TMP
-printf -- "--$BOUNDARY--" >> $TMP
+boundary="---------------------------$(date +%Y%m%d%H%M%S)"
-# upload the certificate to the box
-wget -q -O - $HOST/cgi-bin/firmwarecfg --header="Content-type: multipart/form-data boundary=$BOUNDARY" --post-file $TMP | grep SSL
+cat <<EOD >>"${request_file}"
+--${boundary}
+Content-Disposition: form-data; name="sid"
-# clean up
-rm -f $TMP
+${sid}
+--${boundary}
+Content-Disposition: form-data; name="BoxCertImportFile"; filename="BoxCert.pem"
+Content-Type: application/octet-stream
+
+${certbundle}
+--${boundary}--
+EOD
+
+# upload the certificate to the box
+# shellcheck disable=SC2086
+${CURL_CMD} ${curl_opts} -X POST "${baseurl}/cgi-bin/firmwarecfg" -H "Content-type: multipart/form-data boundary=${boundary}" --data-binary "@${request_file}" | process_curl_output | grep -qE "${SUCCESS_MESSAGES}"
+# shellcheck disable=SC2181
+if [ $? -ne 0 ]; then
+ error "Could not import certificate."
+else
+ echo "Import of the SSL certificate was successful"
+fi