make `fdroid update` check that it can sign the repo, or exit with error

There is no good reason to run unsigned repos any more.  It is trivially
easy to create and use a signed repo, and having to support unsigned repos
in the client makes some security-critical parts of the code a lot more
complicated.

refs #13 https://gitlab.com/fdroid/fdroidserver/issues/13
https://gitlab.com/fdroid/fdroidclient/issues/12
This commit is contained in:
Hans-Christoph Steiner 2015-04-20 19:09:50 -04:00
parent 0d62c3093a
commit 86865faa62
2 changed files with 119 additions and 31 deletions

View File

@ -664,6 +664,36 @@ def scan_apks(apps, apkcache, repodir, knownapks):
repo_pubkey_fingerprint = None
# Generate a certificate fingerprint the same way keytool does it
# (but with slightly different formatting)
def cert_fingerprint(data):
digest = hashlib.sha256(data).digest()
ret = []
ret.append(' '.join("%02X" % ord(b) for b in digest))
return " ".join(ret)
def extract_pubkey():
global repo_pubkey_fingerprint
if 'repo_pubkey' in config:
pubkey = unhexlify(config['repo_pubkey'])
else:
p = FDroidPopen(['keytool', '-exportcert',
'-alias', config['repo_keyalias'],
'-keystore', config['keystore'],
'-storepass:file', config['keystorepassfile']]
+ config['smartcardoptions'], output=False)
if p.returncode != 0 or len(p.output) < 20:
msg = "Failed to get repo pubkey!"
if config['keystore'] == 'NONE':
msg += ' Is your crypto smartcard plugged in?'
logging.critical(msg)
sys.exit(1)
pubkey = p.output
repo_pubkey_fingerprint = cert_fingerprint(pubkey)
return hexlify(pubkey)
def make_index(apps, sortedids, apks, repodir, archive, categories):
"""Make a repo index.
@ -711,38 +741,28 @@ def make_index(apps, sortedids, apks, repodir, archive, categories):
repoel.setAttribute("version", "12")
repoel.setAttribute("timestamp", str(int(time.time())))
if 'repo_keyalias' in config:
# Generate a certificate fingerprint the same way keytool does it
# (but with slightly different formatting)
def cert_fingerprint(data):
digest = hashlib.sha256(data).digest()
ret = []
ret.append(' '.join("%02X" % ord(b) for b in digest))
return " ".join(ret)
def extract_pubkey():
global repo_pubkey_fingerprint
if 'repo_pubkey' in config:
pubkey = unhexlify(config['repo_pubkey'])
else:
p = FDroidPopen(['keytool', '-exportcert',
'-alias', config['repo_keyalias'],
'-keystore', config['keystore'],
'-storepass:file', config['keystorepassfile']]
+ config['smartcardoptions'], output=False)
if p.returncode != 0:
msg = "Failed to get repo pubkey!"
if config['keystore'] == 'NONE':
msg += ' Is your crypto smartcard plugged in?'
logging.critical(msg)
sys.exit(1)
pubkey = p.output
repo_pubkey_fingerprint = cert_fingerprint(pubkey)
return hexlify(pubkey)
repoel.setAttribute("pubkey", extract_pubkey())
nosigningkey = False
if not 'repo_keyalias' in config:
nosigningkey = True
logging.critical("'repo_keyalias' not found in config.py!")
if not 'keystore' in config:
nosigningkey = True
logging.critical("'keystore' not found in config.py!")
if not 'keystorepass' in config:
nosigningkey = True
logging.critical("'keystorepass' not found in config.py!")
if not 'keypass' in config:
nosigningkey = True
logging.critical("'keypass' not found in config.py!")
if not os.path.exists(config['keystore']):
nosigningkey = True
logging.critical("'" + config['keystore'] + "' does not exist!")
if nosigningkey:
logging.warning("`fdroid update` requires a signing key, you can create one using:")
logging.warning("\tfdroid update --create-key")
sys.exit(1)
repoel.setAttribute("pubkey", extract_pubkey())
root.appendChild(repoel)
for appid in sortedids:

View File

@ -325,6 +325,74 @@ $fdroid init --keystore NONE
test -e opensc-fdroid.cfg
test ! -e NONE
#------------------------------------------------------------------------------#
echo_header "setup a new repo with no keystore, add APK, and update"
REPOROOT=`create_test_dir`
KEYSTORE=$REPOROOT/keystore.jks
cd $REPOROOT
touch config.py
touch fdroid-icon.png
mkdir repo/
cp $WORKSPACE/tests/urzip.apk $REPOROOT/
set +e
$fdroid update --create-metadata
if [ $? -eq 0 ]; then
echo "This should have failed because this repo has no keystore!"
exit 1
else
echo "`fdroid update` prompted to add keystore"
fi
set -e
# now set up fake, non-working keystore setup
touch $KEYSTORE
echo "keystore = \"$KEYSTORE\"" >> config.py
echo 'repo_keyalias = "foo"' >> config.py
echo 'keystorepass = "foo"' >> config.py
echo 'keypass = "foo"' >> config.py
set +e
$fdroid update --create-metadata
if [ $? -eq 0 ]; then
echo "This should have failed because this repo has a bad/fake keystore!"
exit 1
else
echo "`fdroid update` prompted to add keystore"
fi
set -e
#------------------------------------------------------------------------------#
echo_header "setup a new repo with keystore with APK, update, then without key"
REPOROOT=`create_test_dir`
KEYSTORE=$REPOROOT/keystore.jks
cd $REPOROOT
$fdroid init --keystore $KEYSTORE
test -e $KEYSTORE
cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
$fdroid update --create-metadata
test -e repo/index.xml
test -e repo/index.jar
grep -F '<application id=' repo/index.xml
# now set fake repo_keyalias
sed -i 's,^ *repo_keyalias.*,repo_keyalias = "fake",' $REPOROOT/config.py
set +e
$fdroid update
if [ $? -eq 0 ]; then
echo "This should have failed because this repo has a bad repo_keyalias!"
exit 1
else
echo "`fdroid update` prompted to add keystore"
fi
set -e
#------------------------------------------------------------------------------#
# remove this to prevent git conflicts and complaining
rm -rf $WORKSPACE/fdroidserver.egg-info/
echo SUCCESS