]>
git.proxmox.com Git - proxmox-acme.git/blob - src/proxmox-acme
5 PROJECT_NAME
="ProxmoxACME"
7 USER_AGENT
="$PROJECT_NAME/$VER"
9 DNS_PLUGIN_PATH
="/usr/share/proxmox-acme/dnsapi"
10 HTTP_HEADER
="$(mktemp)"
15 openssl base64
-e |
tr -d '\r\n'
22 # Usage: hashalg [outputhex]
23 # Output Base64-encoded digest
27 if [ "$alg" = "sha256" ] ||
[ "$alg" = "sha1" ] ||
[ "$alg" = "md5" ]; then
29 openssl dgst
-"$alg" -hex | cut
-d = -f 2 |
tr -d ' '
31 openssl dgst
-"$alg" -binary | _base64
42 # shellcheck disable=SC2018,SC2019
47 # shellcheck disable=SC2018,SC2019
54 echo "$_str" |
grep "^$_sub" >/dev
/null
2>&1
60 echo "$_str" |
grep -- "$_sub\$" >/dev
/null
2>&1
66 echo "$_str" |
grep -- "$_sub" >/dev
/null
2>&1
75 if [ -z "$_sep" ]; then
80 while [ "$_ffi" -gt "0" ]; do
81 _fv
="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
86 _ffi
="$(_math "$_ffi" - 1)"
89 printf -- "%s" "$_str"
95 if eval type type >/dev
/null
2>&1; then
96 type "$cmd" >/dev
/null
2>&1
98 command -v "$cmd" >/dev
/null
2>&1
107 printf "%s" "$(($_m_opts))"
111 if ! egrep -o "$1" 2>/dev
/null
; then
112 sed -n 's/.*\('"$1"'\).*/\1/p'
118 if _contains
"$(xxd --help 2>&1)" "assumes -c30"; then
119 if xxd
-r -p -c 9999 2>/dev
/null
; then
123 if xxd
-r -p 2>/dev
/null
; then
132 _debug2 _URGLY_PRINTF
"$_URGLY_PRINTF"
133 if [ -z "$_URGLY_PRINTF" ]; then
134 if [ "$_ESCAPE_XARGS" ] && _exists
xargs; then
136 echo "$hex" | _upper_case |
sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' |
xargs printf
138 for h
in $
(echo "$hex" | _upper_case |
sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do
146 for c
in $
(echo "$hex" | _upper_case |
sed 's/\([0-9A-F]\)/ \1/g'); do
147 if [ -z "$ic" ]; then
152 ic
="$(_h_char_2_dec "$ic")"
153 jc
="$(_h_char_2_dec "$jc")"
154 printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
162 #Usage: keyfile hashalg
163 #Output: Base64-encoded signature value
167 if [ -z "$alg" ]; then
168 _usage "Usage: _sign keyfile hashalg"
172 _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile "
174 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
175 $_sign_openssl -$alg | _base64
176 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
177 if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then
178 _err "Sign failed: $_sign_openssl"
179 _err "Key file: $keyfile"
180 _err "Key content:$(wc -l <"$keyfile") lines"
183 _debug3 "_signedECText" "$_signedECText"
184 _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
185 _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
186 if [ "$__ECC_KEY_LEN" -eq "256" ]; then
187 while [ "${#_ec_r}" -lt "64" ]; do
190 while [ "${#_ec_s}" -lt "64" ]; do
194 if [ "$__ECC_KEY_LEN" -eq "384" ]; then
195 while [ "${#_ec_r}" -lt "96" ]; do
198 while [ "${#_ec_s}" -lt "96" ]; do
202 if [ "$__ECC_KEY_LEN" -eq "512" ]; then
203 while [ "${#_ec_r}" -lt "132" ]; do
206 while [ "${#_ec_s}" -lt "132" ]; do
210 _debug3 "_ec_r" "$_ec_r"
211 _debug3 "_ec_s" "$_ec_s"
212 printf "%s" "$_ec_r$_ec_s" | _h2b | _base64
214 _err "Unknown key file format."
220 #dummy function because proxmox-acme does not call inithttp
225 # body url [needbase64] [POST|PUT|DELETE] [ContentType]
231 _postContentType="$5"
233 if [ -z "$httpmethod" ]; then
237 _CURL="curl -L --silent --dump-header $HTTP_HEADER -g "
238 if [ "$HTTPS_INSECURE" ]; then
239 _CURL="$_CURL --insecure "
241 if [ "$httpmethod" = "HEAD" ]; then
244 if [ "$needbase64" ]; then
246 if [ "$_postContentType" ]; then
247 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
249 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
252 if [ "$_postContentType" ]; then
253 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
255 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
260 if [ "$_postContentType" ]; then
261 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
263 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
266 if [ "$_postContentType" ]; then
267 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
269 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
274 if [ "$_ret" != "0" ]; then
275 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
277 printf "%s" "$response"
281 # url getheader timeout
287 _CURL="curl -L --silent --dump-header $HTTP_HEADER -g "
288 if [ "$HTTPS_INSECURE" ]; then
289 _CURL="$_CURL --insecure "
292 _CURL="$_CURL --connect-timeout $t"
294 if [ "$onlyheader" ]; then
295 $_CURL -I --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
297 $_CURL --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
300 if [ "$ret" != "0" ]; then
301 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
314 # stdin output hexstr splited by one space
316 # output: " 61 62 63"
318 od -A n -v -t x1 | tr -s " " | sed 's
/ $
//' | tr -d "\r\t\n"
323 _hex_str=$(_hex_dump)
324 for _hex_code in $_hex_str; do
326 case "${_hex_code}" in
532 printf '%%%s
' "$_hex_code"
538 # Usage: hashalg secret_hex [outputhex]
545 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
546 if [ "$outputhex" ]; then
547 (openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
549 openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
557 _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z
' | tr -d 'A-Z
' | tr -d '*.
,-_')
564 if ! _is_idn "$__idn_d"; then
565 printf "%s" "$__idn_d"
570 idn "$__idn_d" | tr -d "\r\n"
572 _err "Please install idn to process IDN names."
577 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
591 stat -c '%U
:%G
' "$1" 2>/dev/null
599 date -u "+%Y-%m-%d %H:%M:%S"
616 printf -- "%s" "[$(date)] " >&1
621 printf -- "%s" "[$(date)] " >&2
637 _readaccountconf_mutable() {
638 _readaccountconf "$1"
642 _clearaccountconf() {
651 if [[ $DEBUG -eq 0 ]]; then
654 printf -- "%s" "[$(date)] " >&1
682 _saveaccountconf_mutable() {
694 _source_plugin_config() {
698 # Proxmox implementation to inject the DNSAPI variables
699 _load_plugin_config() {
700 while IFS= read -r line; do
705 # acme.sh uses eval insted of export
706 if [ -n "$key" ]; then
707 export "$key"="$value"
712 # call setup and teardown direct
713 # the parameter must be set in the correct order
714 # $1 <String> DNS Plugin name
715 # $2 <String> Fully Qualified Domain Name
716 # $3 <String> value for TXT record
717 # $4 <String> DNS plugin auth and config parameter separated by ","
718 # $5 <Integer> 0 is off, and the default all others are on.
722 dns_plugin_path="${DNS_PLUGIN_PATH}/${dns_plugin}.sh"
723 fqdn="_acme-challenge.$2"
725 IFS= read -r txtvalue
726 plugin_conf_string=$4
730 if ! . "$dns_plugin_path"; then
731 _err "Load file $dns_plugin error."
735 addcommand="${dns_plugin}_add"
736 if ! _exists "$addcommand"; then
737 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
741 if ! $addcommand "$fqdn" "$txtvalue"; then
742 _err "Error add txt for domain:$fulldomain"
749 dns_plugin_path="${DNS_PLUGIN_PATH}/${dns_plugin}.sh"
750 fqdn="_acme-challenge.$2"
752 IFS= read -r txtvalue
756 if ! . "$dns_plugin_path"; then
757 _err "Load file $dns_plugin error."
761 rmcommand="${dns_plugin}_rm"
762 if ! _exists "$rmcommand"; then
763 _err "It seems that your api file is not correct, it must have a function named: $rmcommand"
767 if ! $rmcommand "$fqdn" "$txtvalue"; then
768 _err "Error add txt for domain:$fulldomain"