9
9
# changed from ftplicity to duply. #
10
10
# See http://duply.net or http://ftplicity.sourceforge.net/ for more info. #
11
11
# (c) 2006 Christiane Ruetten, Heise Zeitschriften Verlag, Germany #
12
- # (c) 2008-2019 Edgar Soldin (changes since version 1.3) #
12
+ # (c) 2008-2020 Edgar Soldin (changes since version 1.3) #
13
13
# ###############################################################################
14
14
# LICENSE: #
15
15
# This program is licensed under GPLv2. #
33
33
# - import/export profile from/to .tgz function !!!
34
34
#
35
35
# CHANGELOG:
36
+ # 2.3.1 (11.2.2021)
37
+ # - bugfix 123: symmetric encryption errs out, asks for '' private key
38
+ #
39
+ # 2.3 (30.12.2020)
40
+ # - don't import whole key pair anymore if only pub/sec is requested
41
+ # - gpg import routine informs on missing key files in profile now
42
+ # - add check/import needed secret key for decryption
43
+ # - featreq 50: Disable GPG key backups, implemented/added settings
44
+ # GPG_IMPORT/GPG_EXPORT='disabled' to conf template
45
+ #
36
46
# 2.2.2 (24.02.2020)
37
47
# - bugfix 120: Failures in "Autoset trust of key" during restore
38
48
# because of gpg2.2 fingerprint output change
@@ -520,7 +530,7 @@ function python_binary {
520
530
ME_LONG=" $0 "
521
531
ME=" $( basename $0 ) "
522
532
ME_NAME=" ${ME%% .* } "
523
- ME_VERSION=" 2.2.2 "
533
+ ME_VERSION=" 2.3.1 "
524
534
ME_WEBSITE=" http://duply.net"
525
535
526
536
# default config values
@@ -857,6 +867,10 @@ GPG_PW='${DEFAULT_GPG_PW}'
857
867
858
868
# disable preliminary tests with the following setting
859
869
#GPG_TEST='disabled'
870
+ # disable automatic gpg key importing altogether
871
+ #GPG_IMPORT='disabled'
872
+ # disable automatic gpg key exporting to profile folder
873
+ #GPG_EXPORT='disabled'
860
874
861
875
# backend, credentials & location of the backup target (URL-Format)
862
876
# generic syntax is
@@ -1080,25 +1094,15 @@ Hint${hint:+s}:
1080
1094
Don't forget the used _password_ as you will need it.
1081
1095
When done enter the 8 digit id & the password in the profile conf file.
1082
1096
1083
- The key id can be found doing a 'gpg --list-keys'. In the example output
1084
- below the key id would be FFFFFFFF for the public key.
1097
+ The key id can be found doing a 'gpg --list-keys'. In the example output
1098
+ below the key id for the public key would be FFFFFFFF .
1085
1099
1086
1100
pub 1024D/FFFFFFFF 2007-12-17
1087
1101
uid duplicity
1088
1102
sub 2048g/899FE27F 2007-12-17
1089
1103
"
1090
1104
}
1091
1105
1092
- function error_gpg_key {
1093
- local KEY_ID=" $1 "
1094
- local KIND=" $2 "
1095
- error_gpg " ${KIND} gpg key '${KEY_ID} ' cannot be found." \
1096
- " Doublecheck if the above key is listed by 'gpg --list-keys' or available
1097
- as gpg key file '$( basename " $( gpg_keyfile " ${KEY_ID} " ) " ) ' in the profile folder.
1098
- If not you can put it there and $ME_NAME will autoimport it on the next run.
1099
- Alternatively import it manually as the user you plan to run $ME_NAME with."
1100
- }
1101
-
1102
1106
function error_gpg_test {
1103
1107
[ -n " $2 " ] && local hint=" \n $2 \n\n "
1104
1108
@@ -1525,10 +1529,18 @@ function join {
1525
1529
echo $OUT
1526
1530
}
1527
1531
1532
+ function gpg_testing {
1533
+ [ " $GPG_TEST " != " disabled" ]
1534
+ }
1535
+
1528
1536
function gpg_signing {
1529
1537
echo ${GPG_KEY_SIGN} | grep -v -q -e ' ^disabled$'
1530
1538
}
1531
1539
1540
+ function gpg_keytype {
1541
+ echo " $1 " | awk ' /^PUB$/{print "public"}/^SEC$/{print "secret"}'
1542
+ }
1543
+
1532
1544
# parameter key id, key_type
1533
1545
function gpg_keyfile {
1534
1546
local GPG_KEY=$( gpg_key_legalize $1 ) TYPE=" $2 "
@@ -1539,10 +1551,15 @@ function gpg_keyfile {
1539
1551
# parameter key id
1540
1552
function gpg_import {
1541
1553
local i FILE FOUND=0 KEY_ID=" $1 " KEY_TYPE=" $2 " KEY_FP=" " ERR=0
1554
+ [ " $GPG_IMPORT " = " disabled" ] && {
1555
+ echo " Skipping import of needed $( gpg_keytype " $KEY_TYPE " ) key '$KEY_ID '. (GPG_IMPORT='disabled')"
1556
+ return
1557
+ }
1558
+
1542
1559
# create a list of legacy key file names and current naming scheme
1543
1560
# we always import pub and sec if they are avail in conf folder
1544
1561
local KEYFILES=( " $CONFDIR /gpgkey" $( gpg_keyfile " $KEY_ID " ) \
1545
- $( gpg_keyfile " $KEY_ID " PUB ) $( gpg_keyfile " $KEY_ID " SEC ) )
1562
+ $( gpg_keyfile " $KEY_ID " " $KEY_TYPE " ) )
1546
1563
1547
1564
# Try autoimport from existing old gpgkey files
1548
1565
# and new gpgkey.XXX.asc files (since v1.4.2)
@@ -1564,7 +1581,8 @@ function gpg_import {
1564
1581
done
1565
1582
1566
1583
if [ " $FOUND " -eq 0 ]; then
1567
- warning " No keyfile for '$KEY_ID ' found in profile\n'$CONFDIR '."
1584
+ echo " Notice: No keyfile for '$KEY_ID ' found in profile folder."
1585
+ return 1
1568
1586
fi
1569
1587
1570
1588
# try to set trust automagically
@@ -1592,15 +1610,21 @@ function gpg_fingerprint {
1592
1610
}
1593
1611
1594
1612
function gpg_export_if_needed {
1613
+ [ " $GPG_EXPORT " = ' disabled' ] && { \
1614
+ echo " Skipping export of gpg keys. (GPG_EXPORT='disabled')"
1615
+ return
1616
+ }
1617
+
1595
1618
local SUCCESS FILE KEY_TYPE
1596
1619
local TMPFILE=" $TEMP_DIR /${ME_NAME} .$$ .$( date_fix %s) .gpgexp"
1597
1620
for KEY_ID in " $@ " ; do
1598
1621
# check if already exported, do it if not
1599
1622
for KEY_TYPE in PUB SEC; do
1600
1623
FILE=" $( gpg_keyfile " $KEY_ID " $KEY_TYPE ) "
1601
1624
if [ ! -f " $FILE " ] && eval gpg_$( tolower $KEY_TYPE ) _avail \" $KEY_ID \" ; then
1625
+
1602
1626
# exporting
1603
- CMD_MSG=" Backup $KEY_TYPE key '$KEY_ID ' to profile."
1627
+ CMD_MSG=" Backup $( gpg_keytype " $ KEY_TYPE" ) key '$KEY_ID ' to profile."
1604
1628
# gpg2.1 insists on passphrase here, gpg2.0- happily exports w/o it
1605
1629
# we pipe an empty string when GPG_PW is not set to avoid gpg silently waiting for input
1606
1630
run_cmd $( gpg_pass_pipein GPG_PW_SIGN GPG_PW) gpg $GPG_OPTS $GPG_USEAGENT $( gpg_param_passwd GPG_PW_SIGN GPG_PW) --armor --export" $( test " SEC" = " $KEY_TYPE " && echo -secret-keys) " $( qw " $KEY_ID " ) ' >>' $( qw " $TMPFILE " )
@@ -1695,6 +1719,9 @@ function gpg_passwd {
1695
1719
1696
1720
# return success if at least one secret key is available
1697
1721
function gpg_key_decryptable {
1722
+ # no keys, no problem
1723
+ gpg_symmetric && return 0
1724
+
1698
1725
local KEY_ID
1699
1726
for KEY_ID in " ${GPG_KEYS_ENC_ARRAY[@]} " ; do
1700
1727
gpg_sec_avail " $KEY_ID " && return 0
@@ -1715,7 +1742,7 @@ function gpg_param_passwd {
1715
1742
fi
1716
1743
}
1717
1744
1718
- # select the earlist defined and create an "echo <value> |" string
1745
+ # select the earliest defined and create an "echo <value> |" string
1719
1746
function gpg_pass_pipein {
1720
1747
var_isset GPG_USEAGENT && exit 1
1721
1748
@@ -2059,18 +2086,50 @@ Tip: Separate signing keys may have empty passwords e.g. GPG_PW_SIGN=''.
2059
2086
Tip2: Use gpg-agent."
2060
2087
fi
2061
2088
2062
- # check gpg encr public keys availability
2089
+ # test - GPG KEY AVAILABILITY ##################################################
2090
+
2091
+ # check gpg public keys availability, try import if needed
2063
2092
for (( i = 0 ; i < ${# GPG_KEYS_ENC_ARRAY[@]} ; i++ )) ; do
2064
2093
KEY_ID=" ${GPG_KEYS_ENC_ARRAY[$i]} "
2065
2094
# test availability, try to import, retest
2066
2095
if ! gpg_pub_avail " ${KEY_ID} " ; then
2067
- echo " Encryption public key '${KEY_ID} ' not found ."
2096
+ echo " Encryption public key '${KEY_ID} ' not in keychain. Try to import from profile ."
2068
2097
gpg_import " ${KEY_ID} " PUB
2069
2098
gpg_key_cache RESET " ${KEY_ID} "
2070
- gpg_pub_avail " ${KEY_ID} " || error_gpg_key " ${KEY_ID} " " Public"
2099
+ gpg_pub_avail " ${KEY_ID} " || { \
2100
+ gpg_testing && error_gpg \
2101
+ " Needed public gpg key '${KEY_ID} ' is not available in keychain." \
2102
+ " Doublecheck if the above key is listed by 'gpg --list-keys' or available
2103
+ as gpg key file '$( basename " $( gpg_keyfile " ${KEY_ID} " ) " ) ' in the profile folder.
2104
+ If not you can put it there and $ME_NAME will autoimport it on the next run.
2105
+ Alternatively import it manually as the user you plan to run $ME_NAME with."
2106
+ }
2107
+ else
2108
+ echo " Public key '${KEY_ID} ' found in keychain."
2071
2109
fi
2072
2110
done
2073
2111
2112
+ # check gpg encr secret encryption keys availability and fail
2113
+ # if none is available after a round of importing trials
2114
+ gpg_key_decryptable || \
2115
+ {
2116
+ echo " Missing secret keys for decryption in keychain."
2117
+ for (( i = 0 ; i < ${# GPG_KEYS_ENC_ARRAY[@]} ; i++ )) ; do
2118
+ KEY_ID=" ${GPG_KEYS_ENC_ARRAY[$i]} "
2119
+ # test availability, try to import, retest
2120
+ if ! gpg_sec_avail " ${KEY_ID} " ; then
2121
+ echo " Try to import secret key '${KEY_ID} ' from profile."
2122
+ gpg_import " ${KEY_ID} " SEC
2123
+ gpg_key_cache RESET " ${KEY_ID} "
2124
+ fi
2125
+ done
2126
+ gpg_key_decryptable || \
2127
+ {
2128
+ gpg_testing && error_gpg_test " None of the configured keys '$( join " ','" " ${GPG_KEYS_ENC_ARRAY[@]} " ) ' \
2129
+ has a secret key in the keychain. Decryption will be impossible!"
2130
+ }
2131
+ }
2132
+
2074
2133
# gpg secret sign key availability
2075
2134
# if none set, autoset first encryption key as sign key
2076
2135
if ! gpg_signing; then
@@ -2086,6 +2145,7 @@ elif ! var_isset 'GPG_KEY_SIGN'; then
2086
2145
if gpg_sec_avail " ${KEY_ID} " ; then
2087
2146
GPG_KEY_SIGN=" ${KEY_ID} "
2088
2147
else
2148
+ echo " Signing secret key '${KEY_ID} ' not found."
2089
2149
gpg_import " ${KEY_ID} " SEC
2090
2150
gpg_key_cache RESET " ${KEY_ID} "
2091
2151
if gpg_sec_avail " ${KEY_ID} " ; then
@@ -2157,15 +2217,15 @@ echo $@ $DUPL_PARAMS | grep -q -e '--asynchronous-upload' && FACTOR=2 || FACTOR=
2157
2217
# test - GPG SANITY #####################################################################
2158
2218
# if encryption is disabled, skip this whole section
2159
2219
if gpg_disabled; then
2160
- echo -e " Test - En/Decryption skipped. (GPG disabled)"
2161
- elif [ " $GPG_TEST " = " disabled " ] ; then
2162
- echo -e " Test - En/Decryption skipped. (Testing disabled)"
2220
+ echo -e " Test - En/Decryption skipped. (GPG=' disabled' )"
2221
+ elif ! gpg_testing ; then
2222
+ echo -e " Test - En/Decryption skipped. (GPG_TEST=' disabled' )"
2163
2223
else
2164
2224
2165
- GPG_TEST =" $TEMP_DIR /${ME_NAME} .$$ .$( date_fix %s) "
2225
+ GPG_TEST_PREFIX =" $TEMP_DIR /${ME_NAME} .$$ .$( date_fix %s) "
2166
2226
function cleanup_gpgtest {
2167
- echo -en " Cleanup - Delete '${GPG_TEST } _*'"
2168
- rm " ${GPG_TEST } " _* 2> /dev/null && echo " (OK)" || echo " (FAILED)"
2227
+ echo -en " Cleanup - Delete '${GPG_TEST_PREFIX } _*'"
2228
+ rm " ${GPG_TEST_PREFIX } " _* 2> /dev/null && echo " (OK)" || echo " (FAILED)"
2169
2229
}
2170
2230
2171
2231
# signing enabled?
@@ -2182,7 +2242,7 @@ if [ ${#GPG_KEYS_ENC_ARRAY[@]} -gt 0 ]; then
2182
2242
done
2183
2243
# check encrypting
2184
2244
CMD_MSG=" Test - Encrypt to '$( join " ','" " ${GPG_KEYS_ENC_ARRAY[@]} " ) '${CMD_MSG_SIGN: + & $CMD_MSG_SIGN } "
2185
- run_cmd $( gpg_pass_pipein GPG_PW_SIGN GPG_PW) gpg $CMD_PARAM_SIGN $( gpg_param_passwd GPG_PW_SIGN GPG_PW) $CMD_PARAMS $GPG_USEAGENT --status-fd 1 $GPG_OPTS -o $( qw " ${GPG_TEST } _ENC" ) -e $( qw " $ME_LONG " )
2245
+ run_cmd $( gpg_pass_pipein GPG_PW_SIGN GPG_PW) gpg $CMD_PARAM_SIGN $( gpg_param_passwd GPG_PW_SIGN GPG_PW) $CMD_PARAMS $GPG_USEAGENT --status-fd 1 $GPG_OPTS -o $( qw " ${GPG_TEST_PREFIX } _ENC" ) -e $( qw " $ME_LONG " )
2186
2246
CMD_ERR=$?
2187
2247
2188
2248
if [ " $CMD_ERR " != " 0" ]; then
@@ -2196,7 +2256,7 @@ if [ ${#GPG_KEYS_ENC_ARRAY[@]} -gt 0 ]; then
2196
2256
# check decrypting
2197
2257
CMD_MSG=" Test - Decrypt"
2198
2258
gpg_key_decryptable || CMD_DISABLED=" No matching secret key available."
2199
- run_cmd $( gpg_pass_pipein GPG_PW) gpg $( gpg_param_passwd GPG_PW) $GPG_OPTS -o $( qw " ${GPG_TEST } _DEC" ) $GPG_USEAGENT -d $( qw " ${GPG_TEST } _ENC" )
2259
+ run_cmd $( gpg_pass_pipein GPG_PW) gpg $( gpg_param_passwd GPG_PW) $GPG_OPTS -o $( qw " ${GPG_TEST_PREFIX } _DEC" ) $GPG_USEAGENT -d $( qw " ${GPG_TEST_PREFIX } _ENC" )
2200
2260
CMD_ERR=$?
2201
2261
2202
2262
if [ " $CMD_ERR " != " 0" ]; then
@@ -2207,15 +2267,15 @@ if [ ${#GPG_KEYS_ENC_ARRAY[@]} -gt 0 ]; then
2207
2267
else
2208
2268
# check encrypting
2209
2269
CMD_MSG=" Test - Encryption with passphrase${CMD_MSG_SIGN: + & $CMD_MSG_SIGN } "
2210
- run_cmd $( gpg_pass_pipein GPG_PW) gpg $GPG_OPTS $CMD_PARAM_SIGN --passphrase-fd 0 -o $( qw " ${GPG_TEST } _ENC" ) --batch -c $( qw " $ME_LONG " )
2270
+ run_cmd $( gpg_pass_pipein GPG_PW) gpg $GPG_OPTS $CMD_PARAM_SIGN --passphrase-fd 0 -o $( qw " ${GPG_TEST_PREFIX } _ENC" ) --batch -c $( qw " $ME_LONG " )
2211
2271
CMD_ERR=$?
2212
2272
if [ " $CMD_ERR " != " 0" ]; then
2213
2273
error_gpg_test " Encryption failed.${CMD_OUT: +\n $CMD_OUT } "
2214
2274
fi
2215
2275
2216
2276
# check decrypting
2217
2277
CMD_MSG=" Test - Decryption with passphrase"
2218
- run_cmd $( gpg_pass_pipein GPG_PW) gpg $GPG_OPTS --passphrase-fd 0 -o $( qw " ${GPG_TEST } _DEC" ) --batch -d $( qw " ${GPG_TEST } _ENC" )
2278
+ run_cmd $( gpg_pass_pipein GPG_PW) gpg $GPG_OPTS --passphrase-fd 0 -o $( qw " ${GPG_TEST_PREFIX } _DEC" ) --batch -d $( qw " ${GPG_TEST_PREFIX } _ENC" )
2219
2279
CMD_ERR=$?
2220
2280
if [ " $CMD_ERR " != " 0" ]; then
2221
2281
error_gpg_test " Decryption failed.${CMD_OUT: +\n $CMD_OUT } "
2224
2284
2225
2285
# compare original w/ decryptginal
2226
2286
CMD_MSG=" Test - Compare"
2227
- [ -r " ${GPG_TEST } _DEC" ] || CMD_DISABLED=" File not found. Nothing to compare."
2228
- run_cmd " test \"\$ (cat '$ME_LONG ')\" = \"\$ (cat '${GPG_TEST } _DEC')\" "
2287
+ [ -r " ${GPG_TEST_PREFIX } _DEC" ] || CMD_DISABLED=" File not found. Nothing to compare."
2288
+ run_cmd " test \"\$ (cat '$ME_LONG ')\" = \"\$ (cat '${GPG_TEST_PREFIX } _DEC')\" "
2229
2289
CMD_ERR=$?
2230
2290
if [ " $CMD_ERR " = " 0" ]; then
2231
2291
cleanup_gpgtest
0 commit comments