mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-12-24 12:14:23 +08:00
fixes #3359
Ubiquiti removed keytool (and java) from recent releases of Unifi OS. This moves from keytool to openssl's native pkcs12. Tested on Unifi Dream Machine which runs Unifi OS and a built-in Unifi controller. Also added backup of existing files prior to change in case anything goes wrong, and update system configuration with compatible ciphers.
This commit is contained in:
@@ -137,7 +137,8 @@ routeros_deploy() {
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
DEPLOY_SCRIPT_CMD="/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
|
||||
DEPLOY_SCRIPT_CMD=":do {/system script remove \"LECertDeploy-$_cdomain\" } on-error={ }; \
|
||||
/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
|
||||
comment=\"generated by routeros deploy script in acme.sh\" \
|
||||
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
|
||||
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
|
||||
@@ -146,8 +147,8 @@ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
|
||||
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
|
||||
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
|
||||
\ndelay 1;\
|
||||
\n/file remove $_cdomain.cer;\
|
||||
\n/file remove $_cdomain.key;\
|
||||
\n:do {/file remove $_cdomain.cer; } on-error={ }\
|
||||
\n:do {/file remove $_cdomain.key; } on-error={ }\
|
||||
\ndelay 2;\
|
||||
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
|
||||
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
################################################################################
|
||||
# Dependencies:
|
||||
# - curl
|
||||
# - synouser & synogroup (When available and SYNO_USE_TEMP_ADMIN is set)
|
||||
# - synouser & synogroup & synosetkeyvalue (Required for SYNO_USE_TEMP_ADMIN=1)
|
||||
################################################################################
|
||||
# Return value:
|
||||
# 0 means success, otherwise error.
|
||||
@@ -66,14 +66,18 @@ synology_dsm_deploy() {
|
||||
_getdeployconf SYNO_DEVICE_NAME
|
||||
|
||||
# Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
|
||||
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||
_getdeployconf SYNO_USE_TEMP_ADMIN
|
||||
_check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
|
||||
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
if ! _exists synouser || ! _exists synogroup; then
|
||||
_err "Tools are missing for creating temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
if ! _exists synouser || ! _exists synogroup || ! _exists synosetkeyvalue; then
|
||||
_err "Missing required tools to creat temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
_err "Notice: temp admin user authorization method only supports local deployment on DSM."
|
||||
return 1
|
||||
fi
|
||||
if synouser --help 2>&1 | grep -q 'Permission denied'; then
|
||||
_err "For creating temp admin user, the deploy script must be run as root."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -169,7 +173,7 @@ synology_dsm_deploy() {
|
||||
_debug3 H1 "${_H1}"
|
||||
fi
|
||||
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/$api_path?enable_syno_token=yes")
|
||||
_debug3 response "$response"
|
||||
# ## END ## - DEPRECATED, for backward compatibility
|
||||
# If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
|
||||
@@ -184,7 +188,7 @@ synology_dsm_deploy() {
|
||||
_debug SYNO_LOCAL_HOSTNAME "${SYNO_LOCAL_HOSTNAME:-}"
|
||||
if [ "$SYNO_LOCAL_HOSTNAME" != "1" ] && [ "$SYNO_LOCAL_HOSTNAME" == "$SYNO_HOSTNAME" ]; then
|
||||
if [ "$SYNO_HOSTNAME" != "localhost" ] && [ "$SYNO_HOSTNAME" != "127.0.0.1" ]; then
|
||||
_err "SYNO_USE_TEMP_ADMIN=1 Only support locally deployment, if you are sure that hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
|
||||
_err "SYNO_USE_TEMP_ADMIN=1 only support local deployment, though if you are sure that the hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@@ -201,24 +205,27 @@ synology_dsm_deploy() {
|
||||
# shellcheck disable=SC2086
|
||||
synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
|
||||
else
|
||||
_err "Tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
_err "The tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
return 1
|
||||
fi
|
||||
# havig a workaround to temporary disable enforce 2FA-OTP
|
||||
# havig a workaround to temporary disable enforce 2FA-OTP, will restore
|
||||
# it soon (after a single request), though if any accident occurs like
|
||||
# unexpected interruption, this setting can be easily reverted manually.
|
||||
otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
|
||||
if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then
|
||||
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
|
||||
_info "Temporary disabled enforce 2FA-OTP to complete authentication."
|
||||
_info "Enforcing 2FA-OTP has been disabled to complete temp admin authentication."
|
||||
_info "Notice: it will be restored soon, if not, you can restore it manually via Control Panel."
|
||||
_info "previous_otp_enforce_option" "$otp_enforce_option"
|
||||
else
|
||||
otp_enforce_option=""
|
||||
fi
|
||||
fi
|
||||
response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then
|
||||
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option"
|
||||
_info "Restored previous enforce 2FA-OTP option."
|
||||
@@ -227,9 +234,10 @@ synology_dsm_deploy() {
|
||||
fi
|
||||
fi
|
||||
|
||||
error_code=$(echo "$response" | grep '"error"' | grep -oP '(?<="code":)\d+')
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
# Account has 2FA-OTP enabled, since error 403 reported.
|
||||
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Firmware/DSM/All/enu/Synology_DiskStation_Administration_CLI_Guide.pdf
|
||||
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
|
||||
if [ "$error_code" == "403" ]; then
|
||||
if [ -z "$SYNO_DEVICE_NAME" ]; then
|
||||
printf "Enter device name or leave empty for default (CertRenewal): "
|
||||
@@ -261,7 +269,8 @@ synology_dsm_deploy() {
|
||||
_secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||
fi
|
||||
fi
|
||||
error_code=$(echo "$response" | grep '"error"' | grep -oP '(?<="code":)\d+')
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
fi
|
||||
|
||||
if [ -n "$error_code" ]; then
|
||||
@@ -272,12 +281,16 @@ synology_dsm_deploy() {
|
||||
_err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
|
||||
elif [ "$error_code" == "406" ]; then
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
_err "SYNO_USE_TEMP_ADMIN=1 is not supported if enforce auth with 2FA-OTP is enabled."
|
||||
_err "Failed with unexcepted error, please report this by providing full log with '--debug 3'."
|
||||
else
|
||||
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
|
||||
fi
|
||||
elif [ "$error_code" == "400" ] || [ "$error_code" == "401" ] || [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
|
||||
_err "Failed to authenticate with a non-existent or disabled account, or the account password is incorrect or has expired."
|
||||
elif [ "$error_code" == "400" ]; then
|
||||
_err "Failed to authenticate, no such account or incorrect password."
|
||||
elif [ "$error_code" == "401" ]; then
|
||||
_err "Failed to authenticate with a non-existent account."
|
||||
elif [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
|
||||
_err "Failed to authenticate, the account password has expired or must be changed."
|
||||
else
|
||||
_err "Failed to authenticate with error: $error_code."
|
||||
fi
|
||||
@@ -291,7 +304,7 @@ synology_dsm_deploy() {
|
||||
_debug SynoToken "$token"
|
||||
if [ -z "$sid" ] || [ -z "$token" ]; then
|
||||
# Still can't get necessary info even got no errors, may Synology have API updated?
|
||||
_err "Unable to authenticate to $_base_url, you may report the full log to the community."
|
||||
_err "Unable to authenticate to $_base_url, you may report this by providing full log with '--debug 3'."
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
@@ -323,12 +336,13 @@ synology_dsm_deploy() {
|
||||
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\"id\":\"\([^\"]*\).*/\1/p")
|
||||
_debug2 id "$id"
|
||||
|
||||
error_code=$(echo "$response" | grep '"error"' | grep -oP '(?<="code":)\d+')
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
if [ -n "$error_code" ]; then
|
||||
if [ "$error_code" -eq 105 ]; then
|
||||
_err "Current user is not administrator and does not have sufficient permission for deploying."
|
||||
else
|
||||
_err "Failed to fetch certificate info with error: $error_code, please try again or contact Synology to learn more."
|
||||
_err "Failed to fetch certificate info: $error_code, please try again or contact Synology to learn more."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
# - self-hosted Unifi Controller
|
||||
# - Unifi Cloud Key (Gen1/2/2+)
|
||||
# - Unifi Cloud Key running UnifiOS (v2.0.0+, Gen2/2+ only)
|
||||
# - Unifi Dream Machine
|
||||
# This has not been tested on other "all-in-one" devices such as
|
||||
# UDM Pro or Unifi Express.
|
||||
#
|
||||
# OS Version v2.0.0+
|
||||
# Network Application version 7.0.0+
|
||||
# OS version ~3.1 removed java and keytool from the UnifiOS.
|
||||
# Using PKCS12 format keystore appears to work fine.
|
||||
#
|
||||
# Please report bugs to https://github.com/acmesh-official/acme.sh/issues/3359
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
@@ -74,14 +83,16 @@ unifi_deploy() {
|
||||
_reload_cmd=""
|
||||
|
||||
# Unifi Controller environment (self hosted or any Cloud Key) --
|
||||
# auto-detect by file /usr/lib/unifi/data/keystore:
|
||||
# auto-detect by file /usr/lib/unifi/data/keystore
|
||||
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-/usr/lib/unifi/data/keystore}"
|
||||
if [ -f "$_unifi_keystore" ]; then
|
||||
_info "Installing certificate for Unifi Controller (Java keystore)"
|
||||
_debug _unifi_keystore "$_unifi_keystore"
|
||||
if ! _exists keytool; then
|
||||
_err "keytool not found"
|
||||
return 1
|
||||
_do_keytool=0
|
||||
_info "Installing certificate for Unifi Controller (PKCS12 keystore)."
|
||||
else
|
||||
_do_keytool=1
|
||||
_info "Installing certificate for Unifi Controller (Java keystore)"
|
||||
fi
|
||||
if [ ! -w "$_unifi_keystore" ]; then
|
||||
_err "The file $_unifi_keystore is not writable, please change the permission."
|
||||
@@ -92,6 +103,7 @@ unifi_deploy() {
|
||||
|
||||
_debug "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
_debug "_toPkcs $_import_pkcs12 $_ckey $_ccert $_cca $_unifi_keypass unifi root"
|
||||
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
|
||||
# shellcheck disable=SC2181
|
||||
if [ "$?" != "0" ]; then
|
||||
@@ -99,22 +111,57 @@ unifi_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Import into keystore: $_unifi_keystore"
|
||||
if keytool -importkeystore \
|
||||
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
|
||||
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
|
||||
-alias unifi -noprompt; then
|
||||
_debug "Import keystore success!"
|
||||
rm "$_import_pkcs12"
|
||||
# Save the existing keystore in case something goes wrong.
|
||||
mv -f "${_unifi_keystore}" "${_unifi_keystore}"_original
|
||||
_info "Previous keystore saved to ${_unifi_keystore}_original."
|
||||
|
||||
if [ "$_do_keytool" -eq 1 ]; then
|
||||
_debug "Import into keystore: $_unifi_keystore"
|
||||
if keytool -importkeystore \
|
||||
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
|
||||
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
|
||||
-alias unifi -noprompt; then
|
||||
_debug "Import keystore success!"
|
||||
else
|
||||
_err "Error importing into Unifi Java keystore."
|
||||
_err "Please re-run with --debug and report a bug."
|
||||
_info "Restoring original keystore."
|
||||
mv -f "${_unifi_keystore}"_original "${_unifi_keystore}"
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Error importing into Unifi Java keystore."
|
||||
_err "Please re-run with --debug and report a bug."
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
_debug "Copying new keystore to $_unifi_keystore"
|
||||
cp -f "$_import_pkcs12" "$_unifi_keystore"
|
||||
fi
|
||||
|
||||
# Update unifi service for certificate cipher compatibility
|
||||
if ${ACME_OPENSSL_BIN:-openssl} pkcs12 \
|
||||
-in "$_import_pkcs12" \
|
||||
-password pass:aircontrolenterprise \
|
||||
-nokeys | ${ACME_OPENSSL_BIN:-openssl} x509 -text \
|
||||
-noout | grep -i "signature" | grep -iq ecdsa >/dev/null 2>&1; then
|
||||
cp -f /usr/lib/unifi/data/system.properties /usr/lib/unifi/data/system.properties_original
|
||||
_info "Updating system configuration for cipher compatibility."
|
||||
_info "Saved original system config to /usr/lib/unifi/data/system.properties_original"
|
||||
sed -i '/unifi\.https\.ciphers/d' /usr/lib/unifi/data/system.properties
|
||||
echo "unifi.https.ciphers=ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA256" >>/usr/lib/unifi/data/system.properties
|
||||
sed -i '/unifi\.https\.sslEnabledProtocols/d' /usr/lib/unifi/data/system.properties
|
||||
echo "unifi.https.sslEnabledProtocols=TLSv1.3,TLSv1.2" >>/usr/lib/unifi/data/system.properties
|
||||
_info "System configuration updated."
|
||||
fi
|
||||
|
||||
rm "$_import_pkcs12"
|
||||
|
||||
# Restarting unifi-core will bring up unifi, doing it out of order results in
|
||||
# a certificate error, and breaks wifiman.
|
||||
# Restart if we aren't doing unifi-core, otherwise stop for later restart.
|
||||
if systemctl -q is-active unifi; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }service unifi restart"
|
||||
if [ ! -f "${DEPLOY_UNIFI_CORE_CONFIG:-/data/unifi-core/config}/unifi-core.key" ]; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl restart unifi"
|
||||
else
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl stop unifi"
|
||||
fi
|
||||
fi
|
||||
_services_updated="${_services_updated} unifi"
|
||||
_info "Install Unifi Controller certificate success!"
|
||||
@@ -165,6 +212,11 @@ unifi_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save the existing certs in case something goes wrong.
|
||||
cp -f "${_unifi_core_config}"/unifi-core.crt "${_unifi_core_config}"/unifi-core_original.crt
|
||||
cp -f "${_unifi_core_config}"/unifi-core.key "${_unifi_core_config}"/unifi-core_original.key
|
||||
_info "Previous certificate and key saved to ${_unifi_core_config}/unifi-core_original.crt/key."
|
||||
|
||||
cat "$_cfullchain" >"${_unifi_core_config}/unifi-core.crt"
|
||||
cat "$_ckey" >"${_unifi_core_config}/unifi-core.key"
|
||||
|
||||
|
||||
@@ -70,10 +70,10 @@ vault_deploy() {
|
||||
|
||||
# JSON does not allow multiline strings.
|
||||
# So replacing new-lines with "\n" here
|
||||
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
|
||||
_ccert=$(sed -z 's/\n/\\n/g' <"$3")
|
||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
||||
_ckey=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$2")
|
||||
_ccert=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$3")
|
||||
_cca=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$5")
|
||||
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user