chiark / gitweb /
make `fdroid update` check that it can sign the repo, or exit with error
authorHans-Christoph Steiner <hans@eds.org>
Mon, 20 Apr 2015 23:09:50 +0000 (19:09 -0400)
committerHans-Christoph Steiner <hans@eds.org>
Fri, 8 May 2015 20:13:15 +0000 (16:13 -0400)
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

fdroidserver/update.py
tests/run-tests

index f5eee07cfb550e42152cd7d3070c06750bcdb492..2aa1861884493e34061f79531fdc59703f871873 100644 (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:
index d1f988fa64a3f5ef6e0983c272fb6162be80838b..8ee3b6f8d7c3646fbc677ad40bb6d7be20acba09 100755 (executable)
@@ -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