mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-11-04 22:40:29 +03:00
update: AllowedAPKSigningKeys metadata to enforce APK signers
This field lets you specify which signing certificates should be trusted for APKs in a binary repo.
This commit is contained in:
parent
074ea8cae3
commit
3b95d3de64
8 changed files with 165 additions and 1 deletions
|
|
@ -90,6 +90,8 @@ yaml_app_field_order = [
|
|||
'\n',
|
||||
'Builds',
|
||||
'\n',
|
||||
'AllowedAPKSigningKeys',
|
||||
'\n',
|
||||
'MaintainerNotes',
|
||||
'\n',
|
||||
'ArchivePolicy',
|
||||
|
|
@ -145,6 +147,7 @@ class App(dict):
|
|||
self.RepoType = ''
|
||||
self.Repo = ''
|
||||
self.Binaries = None
|
||||
self.AllowedAPKSigningKeys = []
|
||||
self.MaintainerNotes = ''
|
||||
self.ArchivePolicy = None
|
||||
self.AutoUpdateMode = 'None'
|
||||
|
|
@ -199,6 +202,7 @@ fieldtypes = {
|
|||
'MaintainerNotes': TYPE_MULTILINE,
|
||||
'Categories': TYPE_LIST,
|
||||
'AntiFeatures': TYPE_LIST,
|
||||
'AllowedAPKSigningKeys': TYPE_LIST,
|
||||
'Build': TYPE_BUILD,
|
||||
}
|
||||
|
||||
|
|
@ -433,6 +437,10 @@ valuetypes = {
|
|||
r'^http[s]?://',
|
||||
["Binaries"]),
|
||||
|
||||
FieldValidator("AllowedAPKSigningKeys",
|
||||
r'^[a-fA-F0-9]{64}$',
|
||||
["AllowedAPKSigningKeys"]),
|
||||
|
||||
FieldValidator("Archive Policy",
|
||||
r'^[0-9]+ versions$',
|
||||
["ArchivePolicy"]),
|
||||
|
|
@ -927,6 +935,14 @@ def write_yaml(mf, app):
|
|||
cm.update({field: _builds_to_yaml(app)})
|
||||
elif field == 'CurrentVersionCode':
|
||||
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
|
||||
elif field == 'AllowedAPKSigningKeys':
|
||||
value = getattr(app, field)
|
||||
if value:
|
||||
value = [str(i).lower() for i in value]
|
||||
if len(value) == 1:
|
||||
cm.update({field: _field_to_yaml(TYPE_STRING, value[0])})
|
||||
else:
|
||||
cm.update({field: _field_to_yaml(TYPE_LIST, value)})
|
||||
else:
|
||||
cm.update({field: _field_to_yaml(fieldtype(field), getattr(app, field))})
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import yaml
|
|||
import copy
|
||||
from datetime import datetime
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from yaml import CSafeLoader as SafeLoader
|
||||
except ImportError:
|
||||
|
|
@ -51,6 +53,7 @@ from . import metadata
|
|||
from .exception import BuildException, FDroidException
|
||||
|
||||
from PIL import Image, PngImagePlugin
|
||||
|
||||
if hasattr(Image, 'DecompressionBombWarning'):
|
||||
warnings.simplefilter('error', Image.DecompressionBombWarning)
|
||||
Image.MAX_IMAGE_PIXELS = 0xffffff # 4096x4096
|
||||
|
|
@ -688,7 +691,6 @@ def insert_obbs(repodir, apps, apks):
|
|||
list of current, valid apps
|
||||
apks
|
||||
current information on all APKs
|
||||
|
||||
"""
|
||||
def obbWarnDelete(f, msg):
|
||||
logging.warning(msg + ' ' + f)
|
||||
|
|
@ -2223,6 +2225,31 @@ def get_apps_with_packages(apps, apks):
|
|||
return appsWithPackages
|
||||
|
||||
|
||||
def get_apks_without_allowed_signatures(app, apk):
|
||||
"""Check the APK or package has been signed by one of the allowed signing certificates.
|
||||
|
||||
The fingerprint of the signing certificate is the standard X.509
|
||||
SHA-256 fingerprint as a hex string. It can be fetched from an
|
||||
APK using:
|
||||
|
||||
apksigner verify --print-certs my.apk | grep SHA-256
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app
|
||||
The app which declares the AllowedSigningKey
|
||||
apk
|
||||
The APK to check
|
||||
"""
|
||||
if not app or not apk:
|
||||
return
|
||||
allowed_signer_keys = app.get('AllowedAPKSigningKeys', [])
|
||||
if not allowed_signer_keys:
|
||||
return
|
||||
if apk['signer'] not in allowed_signer_keys:
|
||||
return apk['apkName']
|
||||
|
||||
|
||||
def prepare_apps(apps, apks, repodir):
|
||||
"""Encapsulate all necessary preparation steps before we can build an index out of apps and apks.
|
||||
|
||||
|
|
@ -2372,6 +2399,23 @@ def main():
|
|||
appid_has_apks = set()
|
||||
appid_has_repo_files = set()
|
||||
for apk in apks:
|
||||
to_remove = get_apks_without_allowed_signatures(apps.get(apk['packageName']), apk)
|
||||
if to_remove:
|
||||
apks.remove(apk)
|
||||
logging.warning(
|
||||
_('"{path}" is signed by a key that is not allowed:').format(
|
||||
path=to_remove
|
||||
)
|
||||
+ '\n'
|
||||
+ apk['signer']
|
||||
)
|
||||
if options.delete_unknown:
|
||||
for d in repodirs:
|
||||
path = Path(d) / to_remove
|
||||
if path.exists():
|
||||
logging.warning(_('Removing {path}"').format(path=path))
|
||||
path.unlink()
|
||||
|
||||
if apk['apkName'].endswith('.apk'):
|
||||
appid_has_apks.add(apk['packageName'])
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue