From 3829d37d341433c9e30c9069928e3fe6b4d824c1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 4 Apr 2014 00:05:22 -0400 Subject: [PATCH] support repo signing with a key on a smartcard This assumes that the smartcard is already setup with a signing key. init does not generate a key on the smartcard, and skips genkey() if things are configured to use a smartcard. This also does not touch APK signing because that is a much more elaborate question, since each app is signed by its own key. --- examples/opensc-fdroid.cfg | 4 ++++ fdroidserver/init.py | 36 +++++++++++++++++++++++++++++++++++- fdroidserver/update.py | 15 +++++++++------ setup.py | 1 + tests/run-tests.sh | 10 ++++++++++ 5 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 examples/opensc-fdroid.cfg diff --git a/examples/opensc-fdroid.cfg b/examples/opensc-fdroid.cfg new file mode 100644 index 00000000..bf3ef2fd --- /dev/null +++ b/examples/opensc-fdroid.cfg @@ -0,0 +1,4 @@ +name = OpenSC +description = SunPKCS11 w/ OpenSC Smart card Framework +library = /usr/lib/opensc-pkcs11.so +slotListIndex = 1 diff --git a/fdroidserver/init.py b/fdroidserver/init.py index 14d9434d..9571d401 100644 --- a/fdroidserver/init.py +++ b/fdroidserver/init.py @@ -19,6 +19,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import glob import hashlib import os import re @@ -44,6 +45,16 @@ def write_to_config(key, value): with open('config.py', 'w') as f: f.writelines(data) +def disable_in_config(key, value): + '''write a key/value to the local config.py, then comment it out''' + with open('config.py', 'r') as f: + data = f.read() + pattern = '\n[\s#]*' + key + '\s*=\s*"[^"]*"' + repl = '\n#' + key + ' = "' + value + '"' + data = re.sub(pattern, repl, data) + with open('config.py', 'w') as f: + f.writelines(data) + def genpassword(): '''generate a random password for when generating keys''' @@ -196,7 +207,30 @@ def main(): if options.distinguished_name: keydname = options.distinguished_name write_to_config('keydname', keydname) - if not os.path.isfile(keystore): + if keystore == 'NONE': # we're using a smartcard + write_to_config('repo_keyalias', '1') # seems to be the default + disable_in_config('keypass', 'never used with smartcard') + write_to_config('smartcardoptions', + ('-storetype PKCS11 -providerName SunPKCS11-OpenSC ' + + '-providerClass sun.security.pkcs11.SunPKCS11 ' + + '-providerArg opensc-fdroid.cfg')) + # find opensc-pkcs11.so + if not os.path.exists('opensc-fdroid.cfg'): + if os.path.exists('/usr/lib/opensc-pkcs11.so'): + opensc_so = '/usr/lib/opensc-pkcs11.so' + elif os.path.exists('/usr/lib64/opensc-pkcs11.so'): + opensc_so = '/usr/lib64/opensc-pkcs11.so' + else: + files = glob.glob('/usr/lib/' + os.uname()[4] + '-*-gnu/opensc-pkcs11.so') + if len(files) > 0: + opensc_so = files[0] + with open(os.path.join(examplesdir, 'opensc-fdroid.cfg'), 'r') as f: + opensc_fdroid = f.read() + opensc_fdroid = re.sub('^library.*', 'library = ' + opensc_so, opensc_fdroid, + flags=re.MULTILINE) + with open('opensc-fdroid.cfg', 'w') as f: + f.write(opensc_fdroid) + elif not os.path.exists(keystore): # no existing or specified keystore, generate the whole thing keystoredir = os.path.dirname(keystore) if not os.path.exists(keystoredir): diff --git a/fdroidserver/update.py b/fdroidserver/update.py index c386499a..f9d42486 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -796,12 +796,15 @@ def make_index(apps, apks, repodir, archive, categories): sys.exit(1) # Sign the index... - p = FDroidPopen(['jarsigner', '-keystore', config['keystore'], - '-storepass:file', config['keystorepassfile'], - '-keypass:file', config['keypassfile'], - '-digestalg', 'SHA1', '-sigalg', 'MD5withRSA', - os.path.join(repodir, 'index.jar') , config['repo_keyalias']] - + config['smartcardoptions']) + args = ['jarsigner', '-keystore', config['keystore'], + '-storepass:file', config['keystorepassfile'], + '-digestalg', 'SHA1', '-sigalg', 'MD5withRSA', + os.path.join(repodir, 'index.jar'), config['repo_keyalias']] + if config['keystore'] == 'NONE': + args += config['smartcardoptions'] + else: # smardcards never use -keypass + args += ['-keypass:file', config['keypassfile']] + p = FDroidPopen(args) # TODO keypass should be sent via stdin if p.returncode != 0: logging.info("Failed to sign index") diff --git a/setup.py b/setup.py index 3bfea041..35ecc8e5 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ setup(name='fdroidserver', [ 'buildserver/config.buildserver.py', 'examples/config.py', 'examples/makebs.config.py', + 'examples/opensc-fdroid.cfg', 'examples/fdroid-icon.png']), ('fdroidserver/getsig', ['fdroidserver/getsig/getsig.class']) ], diff --git a/tests/run-tests.sh b/tests/run-tests.sh index dbe62eed..c75a2f02 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -49,3 +49,13 @@ $fdroid update -c $fdroid update test -e repo/index.xml test -e repo/index.jar + + +#------------------------------------------------------------------------------# +# setup a new repo from scratch with a HSM/smartcard + +REPOROOT=`mktemp --directory --tmpdir=$WORKSPACE` +cd $REPOROOT +$fdroid init --keystore NONE +test -e opensc-fdroid.cfg +test ! -e NONE