Move index signing methods into signindex.py

This commit is contained in:
Torsten Grote 2017-03-29 12:11:40 -03:00
parent 8f96c9da3d
commit 9f765ed6f7
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
4 changed files with 55 additions and 47 deletions

View file

@ -34,7 +34,6 @@ import logging
import hashlib import hashlib
import socket import socket
import base64 import base64
import zipfile
import xml.etree.ElementTree as XMLElementTree import xml.etree.ElementTree as XMLElementTree
from binascii import hexlify from binascii import hexlify
@ -390,47 +389,6 @@ def write_password_file(pwtype, password=None):
config[pwtype + 'file'] = filename config[pwtype + 'file'] = filename
def signjar(jar):
'''
sign a JAR file with Java's jarsigner.
This does use old hashing algorithms, i.e. SHA1, but that's not
broken yet for file verification. This could be set to SHA256,
but then Android < 4.3 would not be able to verify it.
https://code.google.com/p/android/issues/detail?id=38321
'''
args = [config['jarsigner'], '-keystore', config['keystore'],
'-storepass:file', config['keystorepassfile'],
'-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA',
jar, config['repo_keyalias']]
if config['keystore'] == 'NONE':
args += config['smartcardoptions']
else: # smardcards never use -keypass
args += ['-keypass:file', config['keypassfile']]
p = FDroidPopen(args)
if p.returncode != 0:
logging.critical("Failed to sign %s!" % jar)
sys.exit(1)
def sign_index_v1(repodir, json_name):
"""
sign index-v1.json to make index-v1.jar
This is a bit different than index.jar: instead of their being index.xml
and index_unsigned.jar, the presense of index-v1.json means that there is
unsigned data. That file is then stuck into a jar and signed by the
signing process. index-v1.json is never published to the repo. It is
included in the binary transparency log, if that is enabled.
"""
name, ext = get_extension(json_name)
index_file = os.path.join(repodir, json_name)
jar_file = os.path.join(repodir, name + '.jar')
with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
jar.write(index_file, json_name)
signjar(jar_file)
def get_local_metadata_files(): def get_local_metadata_files():
'''get any metadata files local to an app's source repo '''get any metadata files local to an app's source repo

View file

@ -18,6 +18,7 @@
import sys import sys
import os import os
import zipfile
from argparse import ArgumentParser from argparse import ArgumentParser
import logging import logging
@ -27,6 +28,49 @@ config = None
options = None options = None
def sign_jar(jar):
"""
Sign a JAR file with Java's jarsigner.
This method requires a properly initialized config object.
This does use old hashing algorithms, i.e. SHA1, but that's not
broken yet for file verification. This could be set to SHA256,
but then Android < 4.3 would not be able to verify it.
https://code.google.com/p/android/issues/detail?id=38321
"""
args = [config['jarsigner'], '-keystore', config['keystore'],
'-storepass:file', config['keystorepassfile'],
'-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA',
jar, config['repo_keyalias']]
if config['keystore'] == 'NONE':
args += config['smartcardoptions']
else: # smardcards never use -keypass
args += ['-keypass:file', config['keypassfile']]
p = common.FDroidPopen(args)
if p.returncode != 0:
logging.critical("Failed to sign %s!" % jar)
sys.exit(1)
def sign_index_v1(repodir, json_name):
"""
Sign index-v1.json to make index-v1.jar
This is a bit different than index.jar: instead of their being index.xml
and index_unsigned.jar, the presence of index-v1.json means that there is
unsigned data. That file is then stuck into a jar and signed by the
signing process. index-v1.json is never published to the repo. It is
included in the binary transparency log, if that is enabled.
"""
name, ext = common.get_extension(json_name)
index_file = os.path.join(repodir, json_name)
jar_file = os.path.join(repodir, name + '.jar')
with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
jar.write(index_file, json_name)
sign_jar(jar_file)
def main(): def main():
global config, options global config, options
@ -54,7 +98,7 @@ def main():
unsigned = os.path.join(output_dir, 'index_unsigned.jar') unsigned = os.path.join(output_dir, 'index_unsigned.jar')
if os.path.exists(unsigned): if os.path.exists(unsigned):
common.signjar(unsigned) sign_jar(unsigned)
os.rename(unsigned, os.path.join(output_dir, 'index.jar')) os.rename(unsigned, os.path.join(output_dir, 'index.jar'))
logging.info('Signed index in ' + output_dir) logging.info('Signed index in ' + output_dir)
signed += 1 signed += 1
@ -62,7 +106,7 @@ def main():
json_name = 'index-v1.json' json_name = 'index-v1.json'
index_file = os.path.join(output_dir, json_name) index_file = os.path.join(output_dir, json_name)
if os.path.exists(index_file): if os.path.exists(index_file):
common.sign_index_v1(output_dir, json_name) sign_index_v1(output_dir, json_name)
os.remove(index_file) os.remove(index_file)
logging.info('Signed ' + index_file) logging.info('Signed ' + index_file)
signed += 1 signed += 1

View file

@ -45,6 +45,7 @@ from binascii import hexlify, unhexlify
from PIL import Image from PIL import Image
import logging import logging
from . import signindex
from . import common from . import common
from . import metadata from . import metadata
from .common import FDroidPopen, FDroidPopenBytes, SdkToolsPopen from .common import FDroidPopen, FDroidPopenBytes, SdkToolsPopen
@ -1374,7 +1375,8 @@ def make_index_v1(apps, packages, repodir, repodict, requestsdict):
if options.nosign: if options.nosign:
logging.debug('index-v1 must have a signature, use `fdroid signindex` to create it!') logging.debug('index-v1 must have a signature, use `fdroid signindex` to create it!')
else: else:
common.sign_index_v1(repodir, json_name) signindex.config = config
signindex.sign_index_v1(repodir, json_name)
def make_index_v0(apps, apks, repodir, repodict, requestsdict): def make_index_v0(apps, apks, repodir, repodict, requestsdict):
@ -1626,7 +1628,8 @@ def make_index_v0(apps, apks, repodir, repodict, requestsdict):
if os.path.exists(signed): if os.path.exists(signed):
os.remove(signed) os.remove(signed)
else: else:
common.signjar(signed) signindex.config = config
signindex.sign_jar(signed)
# Copy the repo icon into the repo directory... # Copy the repo icon into the repo directory...
icon_dir = os.path.join(repodir, 'icons') icon_dir = os.path.join(repodir, 'icons')

View file

@ -12,6 +12,8 @@ import tempfile
import unittest import unittest
from zipfile import ZipFile from zipfile import ZipFile
import fdroidserver.signindex
localmodule = os.path.realpath( localmodule = os.path.realpath(
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..')) os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
print('localmodule: ' + localmodule) print('localmodule: ' + localmodule)
@ -163,6 +165,7 @@ class CommonTest(unittest.TestCase):
config = fdroidserver.common.read_config(fdroidserver.common.options) config = fdroidserver.common.read_config(fdroidserver.common.options)
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner') config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')
fdroidserver.common.config = config fdroidserver.common.config = config
fdroidserver.signindex.config = config
basedir = os.path.dirname(__file__) basedir = os.path.dirname(__file__)
tmpdir = os.path.join(basedir, '..', '.testfiles') tmpdir = os.path.join(basedir, '..', '.testfiles')
@ -174,7 +177,7 @@ class CommonTest(unittest.TestCase):
sourcefile = os.path.join(sourcedir, f) sourcefile = os.path.join(sourcedir, f)
testfile = os.path.join(testsdir, f) testfile = os.path.join(testsdir, f)
shutil.copy(sourcefile, testsdir) shutil.copy(sourcefile, testsdir)
fdroidserver.common.signjar(testfile) fdroidserver.signindex.sign_jar(testfile)
# these should be resigned, and therefore different # these should be resigned, and therefore different
self.assertNotEqual(open(sourcefile, 'rb').read(), open(testfile, 'rb').read()) self.assertNotEqual(open(sourcefile, 'rb').read(), open(testfile, 'rb').read())