mirror of
				https://github.com/f-droid/fdroidserver.git
				synced 2025-11-04 06:30:27 +03:00 
			
		
		
		
	publish: always use apksigner to sign APKs, closes #880
This commit is contained in:
		
							parent
							
								
									08cde5c2e6
								
							
						
					
					
						commit
						50f0534d87
					
				
					 1 changed files with 38 additions and 73 deletions
				
			
		| 
						 | 
				
			
			@ -3001,7 +3001,7 @@ def _zipalign(unsigned_apk, aligned_apk):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def apk_implant_signatures(apkpath, signaturefile, signedfile, manifest):
 | 
			
		||||
    """Implats a signature from metadata into an APK.
 | 
			
		||||
    """Implants a signature from metadata into an APK.
 | 
			
		||||
 | 
			
		||||
    Note: this changes there supplied APK in place. So copy it if you
 | 
			
		||||
    need the original to be preserved.
 | 
			
		||||
| 
						 | 
				
			
			@ -3061,82 +3061,47 @@ def get_min_sdk_version(apk):
 | 
			
		|||
def sign_apk(unsigned_path, signed_path, keyalias):
 | 
			
		||||
    """Sign and zipalign an unsigned APK, then save to a new file, deleting the unsigned
 | 
			
		||||
 | 
			
		||||
    Use apksigner for making v2 and v3 signature for apks with targetSDK >=30 as
 | 
			
		||||
    otherwise they won't be installable on Android 11/R.
 | 
			
		||||
    NONE is a Java keyword used to configure smartcards as the
 | 
			
		||||
    keystore.  Otherwise, the keystore is a local file.
 | 
			
		||||
    https://docs.oracle.com/javase/7/docs/technotes/guides/security/p11guide.html#KeyToolJarSigner
 | 
			
		||||
 | 
			
		||||
    Otherwise use jarsigner for v1 only signatures until we have apksig v2/v3
 | 
			
		||||
    signature transplantig support.
 | 
			
		||||
 | 
			
		||||
    When using jarsigner we need to manually select the hash algorithm,
 | 
			
		||||
    apksigner does this automatically. Apksigner also does the zipalign for us.
 | 
			
		||||
 | 
			
		||||
    SHA-256 support was added in android-18 (4.3), before then, the only options were MD5
 | 
			
		||||
    and SHA1. This aims to use SHA-256 when the APK does not target
 | 
			
		||||
    older Android versions, and is therefore safe to do so.
 | 
			
		||||
 | 
			
		||||
    https://issuetracker.google.com/issues/36956587
 | 
			
		||||
    https://android-review.googlesource.com/c/platform/libcore/+/44491
 | 
			
		||||
    When using smartcards, apksigner does not use the same options has
 | 
			
		||||
    Java/keytool/jarsigner (-providerName, -providerClass,
 | 
			
		||||
    -providerArg, -storetype).  apksigner documents the options as
 | 
			
		||||
    --ks-provider-class and --ks-provider-arg.  Those seem to be
 | 
			
		||||
    accepted but fail when actually making a signature with weird
 | 
			
		||||
    internal exceptions. We use the options that actually work.  From:
 | 
			
		||||
    https://geoffreymetais.github.io/code/key-signing/#scripting
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    apk = _get_androguard_APK(unsigned_path)
 | 
			
		||||
    if apk.get_effective_target_sdk_version() >= 30:
 | 
			
		||||
        if config['keystore'] == 'NONE':
 | 
			
		||||
            # NOTE: apksigner doesn't like -providerName/--provider-name at all, don't use that.
 | 
			
		||||
            #       apksigner documents the options as --ks-provider-class and --ks-provider-arg
 | 
			
		||||
            #       those seem to be accepted but fail when actually making a signature with
 | 
			
		||||
            #       weird internal exceptions. Those options actually work.
 | 
			
		||||
            #       From: https://geoffreymetais.github.io/code/key-signing/#scripting
 | 
			
		||||
            apksigner_smartcardoptions = config['smartcardoptions'].copy()
 | 
			
		||||
            if '-providerName' in apksigner_smartcardoptions:
 | 
			
		||||
                pos = config['smartcardoptions'].index('-providerName')
 | 
			
		||||
                # remove -providerName and it's argument
 | 
			
		||||
                del apksigner_smartcardoptions[pos]
 | 
			
		||||
                del apksigner_smartcardoptions[pos]
 | 
			
		||||
            replacements = {'-storetype': '--ks-type',
 | 
			
		||||
                            '-providerClass': '--provider-class',
 | 
			
		||||
                            '-providerArg': '--provider-arg'}
 | 
			
		||||
            signing_args = [replacements.get(n, n) for n in apksigner_smartcardoptions]
 | 
			
		||||
        else:
 | 
			
		||||
            signing_args = ['--key-pass', 'env:FDROID_KEY_PASS']
 | 
			
		||||
        if not find_apksigner():
 | 
			
		||||
            raise BuildException(_("apksigner not found, it's required for signing!"))
 | 
			
		||||
        cmd = [find_apksigner(), 'sign',
 | 
			
		||||
               '--ks', config['keystore'],
 | 
			
		||||
               '--ks-pass', 'env:FDROID_KEY_STORE_PASS']
 | 
			
		||||
        cmd += signing_args
 | 
			
		||||
        cmd += ['--ks-key-alias', keyalias,
 | 
			
		||||
                '--in', unsigned_path,
 | 
			
		||||
                '--out', signed_path]
 | 
			
		||||
        p = FDroidPopen(cmd, envs={
 | 
			
		||||
            'FDROID_KEY_STORE_PASS': config['keystorepass'],
 | 
			
		||||
            'FDROID_KEY_PASS': config.get('keypass', "")})
 | 
			
		||||
        if p.returncode != 0:
 | 
			
		||||
            raise BuildException(_("Failed to sign application"), p.output)
 | 
			
		||||
        os.remove(unsigned_path)
 | 
			
		||||
    if config['keystore'] == 'NONE':
 | 
			
		||||
        apksigner_smartcardoptions = config['smartcardoptions'].copy()
 | 
			
		||||
        if '-providerName' in apksigner_smartcardoptions:
 | 
			
		||||
            pos = config['smartcardoptions'].index('-providerName')
 | 
			
		||||
            # remove -providerName and it's argument
 | 
			
		||||
            del apksigner_smartcardoptions[pos]
 | 
			
		||||
            del apksigner_smartcardoptions[pos]
 | 
			
		||||
        replacements = {'-storetype': '--ks-type',
 | 
			
		||||
                        '-providerClass': '--provider-class',
 | 
			
		||||
                        '-providerArg': '--provider-arg'}
 | 
			
		||||
        signing_args = [replacements.get(n, n) for n in apksigner_smartcardoptions]
 | 
			
		||||
    else:
 | 
			
		||||
 | 
			
		||||
        if get_min_sdk_version(apk) < 18:
 | 
			
		||||
            signature_algorithm = ['-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1']
 | 
			
		||||
        else:
 | 
			
		||||
            signature_algorithm = ['-sigalg', 'SHA256withRSA', '-digestalg', 'SHA-256']
 | 
			
		||||
        if config['keystore'] == 'NONE':
 | 
			
		||||
            signing_args = config['smartcardoptions']
 | 
			
		||||
        else:
 | 
			
		||||
            signing_args = ['-keypass:env', 'FDROID_KEY_PASS']
 | 
			
		||||
 | 
			
		||||
        cmd = [config['jarsigner'], '-keystore', config['keystore'],
 | 
			
		||||
               '-storepass:env', 'FDROID_KEY_STORE_PASS']
 | 
			
		||||
        cmd += signing_args
 | 
			
		||||
        cmd += signature_algorithm
 | 
			
		||||
        cmd += [unsigned_path, keyalias]
 | 
			
		||||
        p = FDroidPopen(cmd, envs={
 | 
			
		||||
            'FDROID_KEY_STORE_PASS': config['keystorepass'],
 | 
			
		||||
            'FDROID_KEY_PASS': config.get('keypass', "")})
 | 
			
		||||
        if p.returncode != 0:
 | 
			
		||||
            raise BuildException(_("Failed to sign application"), p.output)
 | 
			
		||||
 | 
			
		||||
        _zipalign(unsigned_path, signed_path)
 | 
			
		||||
        os.remove(unsigned_path)
 | 
			
		||||
        signing_args = ['--key-pass', 'env:FDROID_KEY_PASS']
 | 
			
		||||
    if not find_apksigner():
 | 
			
		||||
        raise BuildException(_("apksigner not found, it's required for signing!"))
 | 
			
		||||
    cmd = [find_apksigner(), 'sign',
 | 
			
		||||
           '--ks', config['keystore'],
 | 
			
		||||
           '--ks-pass', 'env:FDROID_KEY_STORE_PASS']
 | 
			
		||||
    cmd += signing_args
 | 
			
		||||
    cmd += ['--ks-key-alias', keyalias,
 | 
			
		||||
            '--in', unsigned_path,
 | 
			
		||||
            '--out', signed_path]
 | 
			
		||||
    p = FDroidPopen(cmd, envs={
 | 
			
		||||
        'FDROID_KEY_STORE_PASS': config['keystorepass'],
 | 
			
		||||
        'FDROID_KEY_PASS': config.get('keypass', "")})
 | 
			
		||||
    if p.returncode != 0:
 | 
			
		||||
        raise BuildException(_("Failed to sign application"), p.output)
 | 
			
		||||
    os.remove(unsigned_path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def verify_apks(signed_apk, unsigned_apk, tmp_dir):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue