Search in sources :

Example 1 with SigningCertificateLineage

use of com.android.apksig.SigningCertificateLineage in project AppManager by MuntashirAkon.

the class AppDetailsViewModel method loadSignatures.

@SuppressWarnings("deprecation")
@WorkerThread
private void loadSignatures() {
    List<AppDetailsItem<X509Certificate>> appDetailsItems = new ArrayList<>();
    if (mApkFile == null) {
        mSignatures.postValue(appDetailsItems);
        return;
    }
    try {
        File idsigFile = mApkFile.getIdsigFile();
        ApkVerifier.Builder builder = new ApkVerifier.Builder(mApkFile.getBaseEntry().getRealCachedFile());
        if (idsigFile != null) {
            builder.setV4SignatureFile(idsigFile);
        }
        ApkVerifier apkVerifier = builder.build();
        mApkVerifierResult = apkVerifier.verify();
        // Get signer certificates
        List<X509Certificate> certificates = mApkVerifierResult.getSignerCertificates();
        if (certificates != null && certificates.size() > 0) {
            for (X509Certificate certificate : certificates) {
                AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);
                item.name = "Signer Certificate";
                appDetailsItems.add(item);
            }
            if (mIsExternalApk && mPackageInfo.signatures == null) {
                List<Signature> signatures = new ArrayList<>(certificates.size());
                for (X509Certificate certificate : certificates) {
                    try {
                        signatures.add(new Signature(certificate.getEncoded()));
                    } catch (CertificateEncodingException ignore) {
                    }
                }
                mPackageInfo.signatures = signatures.toArray(new Signature[0]);
            }
        } else {
            // noinspection ConstantConditions Null is deliberately set here to get at least one row
            appDetailsItems.add(new AppDetailsItem<>(null));
        }
        // Get source stamp certificate
        if (mApkVerifierResult.isSourceStampVerified()) {
            ApkVerifier.Result.SourceStampInfo sourceStampInfo = mApkVerifierResult.getSourceStampInfo();
            X509Certificate certificate = sourceStampInfo.getCertificate();
            if (certificate != null) {
                AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);
                item.name = "SourceStamp Certificate";
                appDetailsItems.add(item);
            }
        }
        SigningCertificateLineage lineage = mApkVerifierResult.getSigningCertificateLineage();
        if (lineage != null) {
            certificates = lineage.getCertificatesInLineage();
            if (certificates != null && certificates.size() > 0) {
                for (X509Certificate certificate : certificates) {
                    AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);
                    item.name = "Certificate for Lineage";
                    appDetailsItems.add(item);
                }
            }
        }
    } catch (IOException | ApkFormatException | NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    mSignatures.postValue(appDetailsItems);
}
Also used : ArrayList(java.util.ArrayList) CertificateEncodingException(java.security.cert.CertificateEncodingException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) AppDetailsItem(io.github.muntashirakon.AppManager.details.struct.AppDetailsItem) X509Certificate(java.security.cert.X509Certificate) SigningCertificateLineage(com.android.apksig.SigningCertificateLineage) ApkVerifier(com.android.apksig.ApkVerifier) ApkFormatException(com.android.apksig.apk.ApkFormatException) Signature(android.content.pm.Signature) ApkFile(io.github.muntashirakon.AppManager.apk.ApkFile) File(java.io.File) WorkerThread(androidx.annotation.WorkerThread)

Example 2 with SigningCertificateLineage

use of com.android.apksig.SigningCertificateLineage in project bundletool by google.

the class BuildApksCommandTest method populateLineage_apkFile.

@Test
public void populateLineage_apkFile() throws Exception {
    SigningCertificateLineage.SignerConfig signerConfig = new SigningCertificateLineage.SignerConfig.Builder(privateKey, certificate).build();
    SigningCertificateLineage.SignerConfig oldestSignerConfig = new SigningCertificateLineage.SignerConfig.Builder(oldestSignerPrivateKey, oldestSignerCertificate).build();
    SigningCertificateLineage lineage = new SigningCertificateLineage.Builder(oldestSignerConfig, signerConfig).build();
    com.android.tools.build.bundletool.model.SignerConfig oldestSigner = com.android.tools.build.bundletool.model.SignerConfig.builder().setPrivateKey(oldestSignerPrivateKey).setCertificates(ImmutableList.of(oldestSignerCertificate)).build();
    TestComponent.useTestModule(this, TestModule.builder().withSigningConfig(SigningConfiguration.builder().setSignerConfig(privateKey, certificate).setSigningCertificateLineage(lineage).setOldestSigner(oldestSigner).build()).build());
    File lineageFile = createMinimalistSignedApkFile().toFile();
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    BuildApksCommand commandViaFlags = BuildApksCommand.fromFlags(new FlagParser().parse("--bundle=" + bundlePath, "--output=" + outputFilePath, "--aapt2=" + AAPT2_PATH, "--ks=" + keystorePath, "--ks-key-alias=" + KEY_ALIAS, "--ks-pass=pass:" + KEYSTORE_PASSWORD, "--key-pass=pass:" + KEY_PASSWORD, "--lineage=" + lineageFile, "--oldest-signer=" + oldestSignerPropertiesPath), new PrintStream(output), systemEnvironmentProvider, fakeAdbServer);
    SigningConfiguration signingConfiguration = commandViaFlags.getSigningConfiguration().get();
    assertThat(signingConfiguration.getSigningCertificateLineage().get().getCertificatesInLineage()).containsExactly(oldestSignerCertificate, certificate);
    assertThat(signingConfiguration.getOldestSigner().get().getPrivateKey()).isEqualTo(oldestSignerConfig.getPrivateKey());
    assertThat(signingConfiguration.getOldestSigner().get().getCertificates()).containsExactly(oldestSignerConfig.getCertificate());
}
Also used : PrintStream(java.io.PrintStream) ApksigSigningConfiguration(com.android.tools.build.bundletool.model.ApksigSigningConfiguration) SigningConfiguration(com.android.tools.build.bundletool.model.SigningConfiguration) ByteArrayOutputStream(java.io.ByteArrayOutputStream) SigningCertificateLineage(com.android.apksig.SigningCertificateLineage) SignerConfig(com.android.tools.build.bundletool.model.SignerConfig) SignerConfig(com.android.tools.build.bundletool.model.SignerConfig) FlagParser(com.android.tools.build.bundletool.flags.FlagParser) DeviceFactory.createDeviceSpecFile(com.android.tools.build.bundletool.testing.DeviceFactory.createDeviceSpecFile) File(java.io.File) CodeRelatedFile(com.android.bundle.CodeTransparencyOuterClass.CodeRelatedFile) Test(org.junit.Test)

Example 3 with SigningCertificateLineage

use of com.android.apksig.SigningCertificateLineage in project apksig by venshine.

the class ApkSignerTool method sign.

// END-AOSP
private static void sign(String[] params) throws Exception {
    if (params.length == 0) {
        printUsage(HELP_PAGE_SIGN);
        return;
    }
    File outputApk = null;
    File inputApk = null;
    boolean verbose = false;
    boolean v1SigningEnabled = true;
    boolean v2SigningEnabled = true;
    boolean v3SigningEnabled = true;
    boolean v4SigningEnabled = true;
    boolean forceSourceStampOverwrite = false;
    boolean verityEnabled = false;
    boolean debuggableApkPermitted = true;
    int minSdkVersion = 1;
    boolean minSdkVersionSpecified = false;
    int maxSdkVersion = Integer.MAX_VALUE;
    List<SignerParams> signers = new ArrayList<>(1);
    SignerParams signerParams = new SignerParams();
    SigningCertificateLineage lineage = null;
    SignerParams sourceStampSignerParams = new SignerParams();
    SigningCertificateLineage sourceStampLineage = null;
    List<ProviderInstallSpec> providers = new ArrayList<>();
    ProviderInstallSpec providerParams = new ProviderInstallSpec();
    OptionsParser optionsParser = new OptionsParser(params);
    String optionName;
    String optionOriginalForm = null;
    boolean v4SigningFlagFound = false;
    boolean sourceStampFlagFound = false;
    boolean deterministicDsaSigning = false;
    boolean otherSignersSignaturesPreserved = false;
    while ((optionName = optionsParser.nextOption()) != null) {
        optionOriginalForm = optionsParser.getOptionOriginalForm();
        if (("help".equals(optionName)) || ("h".equals(optionName))) {
            printUsage(HELP_PAGE_SIGN);
            return;
        } else if ("out".equals(optionName)) {
            outputApk = new File(optionsParser.getRequiredValue("Output file name"));
        } else if ("in".equals(optionName)) {
            inputApk = new File(optionsParser.getRequiredValue("Input file name"));
        } else if ("min-sdk-version".equals(optionName)) {
            minSdkVersion = optionsParser.getRequiredIntValue("Mininimum API Level");
            minSdkVersionSpecified = true;
        } else if ("max-sdk-version".equals(optionName)) {
            maxSdkVersion = optionsParser.getRequiredIntValue("Maximum API Level");
        } else if ("v1-signing-enabled".equals(optionName)) {
            v1SigningEnabled = optionsParser.getOptionalBooleanValue(true);
        } else if ("v2-signing-enabled".equals(optionName)) {
            v2SigningEnabled = optionsParser.getOptionalBooleanValue(true);
        } else if ("v3-signing-enabled".equals(optionName)) {
            v3SigningEnabled = optionsParser.getOptionalBooleanValue(true);
        } else if ("v4-signing-enabled".equals(optionName)) {
            v4SigningEnabled = optionsParser.getOptionalBooleanValue(true);
            v4SigningFlagFound = true;
        } else if ("force-stamp-overwrite".equals(optionName)) {
            forceSourceStampOverwrite = optionsParser.getOptionalBooleanValue(true);
        } else if ("verity-enabled".equals(optionName)) {
            verityEnabled = optionsParser.getOptionalBooleanValue(true);
        } else if ("debuggable-apk-permitted".equals(optionName)) {
            debuggableApkPermitted = optionsParser.getOptionalBooleanValue(true);
        } else if ("next-signer".equals(optionName)) {
            if (!signerParams.isEmpty()) {
                signers.add(signerParams);
                signerParams = new SignerParams();
            }
        } else if ("ks".equals(optionName)) {
            signerParams.setKeystoreFile(optionsParser.getRequiredValue("KeyStore file"));
        } else if ("ks-key-alias".equals(optionName)) {
            signerParams.setKeystoreKeyAlias(optionsParser.getRequiredValue("KeyStore key alias"));
        } else if ("ks-pass".equals(optionName)) {
            signerParams.setKeystorePasswordSpec(optionsParser.getRequiredValue("KeyStore password"));
        } else if ("key-pass".equals(optionName)) {
            signerParams.setKeyPasswordSpec(optionsParser.getRequiredValue("Key password"));
        } else if ("pass-encoding".equals(optionName)) {
            String charsetName = optionsParser.getRequiredValue("Password character encoding");
            try {
                signerParams.setPasswordCharset(PasswordRetriever.getCharsetByName(charsetName));
            } catch (IllegalArgumentException e) {
                throw new ParameterException("Unsupported password character encoding requested using" + " --pass-encoding: " + charsetName);
            }
        } else if ("v1-signer-name".equals(optionName)) {
            signerParams.setV1SigFileBasename(optionsParser.getRequiredValue("JAR signature file basename"));
        } else if ("ks-type".equals(optionName)) {
            signerParams.setKeystoreType(optionsParser.getRequiredValue("KeyStore type"));
        } else if ("ks-provider-name".equals(optionName)) {
            signerParams.setKeystoreProviderName(optionsParser.getRequiredValue("JCA KeyStore Provider name"));
        } else if ("ks-provider-class".equals(optionName)) {
            signerParams.setKeystoreProviderClass(optionsParser.getRequiredValue("JCA KeyStore Provider class name"));
        } else if ("ks-provider-arg".equals(optionName)) {
            signerParams.setKeystoreProviderArg(optionsParser.getRequiredValue("JCA KeyStore Provider constructor argument"));
        } else if ("key".equals(optionName)) {
            signerParams.setKeyFile(optionsParser.getRequiredValue("Private key file"));
        } else if ("cert".equals(optionName)) {
            signerParams.setCertFile(optionsParser.getRequiredValue("Certificate file"));
        } else if ("lineage".equals(optionName)) {
            File lineageFile = new File(optionsParser.getRequiredValue("Lineage File"));
            lineage = getLineageFromInputFile(lineageFile);
        } else if ("v".equals(optionName) || "verbose".equals(optionName)) {
            verbose = optionsParser.getOptionalBooleanValue(true);
        } else if ("next-provider".equals(optionName)) {
            if (!providerParams.isEmpty()) {
                providers.add(providerParams);
                providerParams = new ProviderInstallSpec();
            }
        } else if ("provider-class".equals(optionName)) {
            providerParams.className = optionsParser.getRequiredValue("JCA Provider class name");
        } else if ("provider-arg".equals(optionName)) {
            providerParams.constructorParam = optionsParser.getRequiredValue("JCA Provider constructor argument");
        } else if ("provider-pos".equals(optionName)) {
            providerParams.position = optionsParser.getRequiredIntValue("JCA Provider position");
        } else if ("stamp-signer".equals(optionName)) {
            sourceStampFlagFound = true;
            sourceStampSignerParams = processSignerParams(optionsParser);
        } else if ("stamp-lineage".equals(optionName)) {
            File stampLineageFile = new File(optionsParser.getRequiredValue("Stamp Lineage File"));
            sourceStampLineage = getLineageFromInputFile(stampLineageFile);
        } else if ("deterministic-dsa-signing".equals(optionName)) {
            deterministicDsaSigning = optionsParser.getOptionalBooleanValue(false);
        } else if ("append-signature".equals(optionName)) {
            otherSignersSignaturesPreserved = optionsParser.getOptionalBooleanValue(true);
        } else {
            throw new ParameterException("Unsupported option: " + optionOriginalForm + ". See --help for supported" + " options.");
        }
    }
    if (!signerParams.isEmpty()) {
        signers.add(signerParams);
    }
    signerParams = null;
    if (!providerParams.isEmpty()) {
        providers.add(providerParams);
    }
    providerParams = null;
    if (signers.isEmpty()) {
        throw new ParameterException("At least one signer must be specified");
    }
    params = optionsParser.getRemainingParams();
    if (inputApk != null) {
        // parameters.
        if (params.length > 0) {
            throw new ParameterException("Unexpected parameter(s) after " + optionOriginalForm + ": " + params[0]);
        }
    } else {
        // supposed to be the path to input APK.
        if (params.length < 1) {
            throw new ParameterException("Missing input APK");
        } else if (params.length > 1) {
            throw new ParameterException("Unexpected parameter(s) after input APK (" + params[1] + ")");
        }
        inputApk = new File(params[0]);
    }
    if ((minSdkVersionSpecified) && (minSdkVersion > maxSdkVersion)) {
        throw new ParameterException("Min API Level (" + minSdkVersion + ") > max API Level (" + maxSdkVersion + ")");
    }
    // Install additional JCA Providers
    for (ProviderInstallSpec providerInstallSpec : providers) {
        providerInstallSpec.installProvider();
    }
    ApkSigner.SignerConfig sourceStampSignerConfig = null;
    List<ApkSigner.SignerConfig> signerConfigs = new ArrayList<>(signers.size());
    int signerNumber = 0;
    try (PasswordRetriever passwordRetriever = new PasswordRetriever()) {
        for (SignerParams signer : signers) {
            signerNumber++;
            signer.setName("signer #" + signerNumber);
            ApkSigner.SignerConfig signerConfig = getSignerConfig(signer, passwordRetriever, deterministicDsaSigning);
            if (signerConfig == null) {
                return;
            }
            signerConfigs.add(signerConfig);
        }
        if (sourceStampFlagFound) {
            sourceStampSignerParams.setName("stamp signer");
            sourceStampSignerConfig = getSignerConfig(sourceStampSignerParams, passwordRetriever, deterministicDsaSigning);
            if (sourceStampSignerConfig == null) {
                return;
            }
        }
    }
    if (outputApk == null) {
        outputApk = inputApk;
    }
    File tmpOutputApk;
    if (inputApk.getCanonicalPath().equals(outputApk.getCanonicalPath())) {
        tmpOutputApk = File.createTempFile("apksigner", ".apk");
        tmpOutputApk.deleteOnExit();
    } else {
        tmpOutputApk = outputApk;
    }
    ApkSigner.Builder apkSignerBuilder = new ApkSigner.Builder(signerConfigs).setInputApk(inputApk).setOutputApk(tmpOutputApk).setOtherSignersSignaturesPreserved(otherSignersSignaturesPreserved).setV1SigningEnabled(v1SigningEnabled).setV2SigningEnabled(v2SigningEnabled).setV3SigningEnabled(v3SigningEnabled).setV4SigningEnabled(v4SigningEnabled).setForceSourceStampOverwrite(forceSourceStampOverwrite).setVerityEnabled(verityEnabled).setV4ErrorReportingEnabled(v4SigningEnabled && v4SigningFlagFound).setDebuggableApkPermitted(debuggableApkPermitted).setSigningCertificateLineage(lineage);
    if (minSdkVersionSpecified) {
        apkSignerBuilder.setMinSdkVersion(minSdkVersion);
    }
    if (v4SigningEnabled) {
        final File outputV4SignatureFile = new File(outputApk.getCanonicalPath() + ".idsig");
        Files.deleteIfExists(outputV4SignatureFile.toPath());
        apkSignerBuilder.setV4SignatureOutputFile(outputV4SignatureFile);
    }
    if (sourceStampSignerConfig != null) {
        apkSignerBuilder.setSourceStampSignerConfig(sourceStampSignerConfig).setSourceStampSigningCertificateLineage(sourceStampLineage);
    }
    ApkSigner apkSigner = apkSignerBuilder.build();
    try {
        apkSigner.sign();
    } catch (MinSdkVersionException e) {
        String msg = e.getMessage();
        if (!msg.endsWith(".")) {
            msg += '.';
        }
        throw new MinSdkVersionException("Failed to determine APK's minimum supported platform version" + ". Use --min-sdk-version to override", e);
    }
    if (!tmpOutputApk.getCanonicalPath().equals(outputApk.getCanonicalPath())) {
        Files.move(tmpOutputApk.toPath(), outputApk.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }
    if (verbose) {
        System.out.println("Signed");
    }
}
Also used : ArrayList(java.util.ArrayList) SigningCertificateLineage(com.android.apksig.SigningCertificateLineage) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File) ApkSigner(com.android.apksig.ApkSigner) MinSdkVersionException(com.android.apksig.apk.MinSdkVersionException)

Example 4 with SigningCertificateLineage

use of com.android.apksig.SigningCertificateLineage in project apksig by venshine.

the class V3SchemeVerifier method parseSigner.

/**
 * Parses the provided signer block and populates the {@code result}.
 *
 * <p>This verifies signatures over {@code signed-data} contained in this block, as well as
 * the data contained therein, but does not verify the integrity of the rest of the APK. To
 * facilitate APK integrity verification, this method adds the {@code contentDigestsToVerify}.
 * These digests can then be used to verify the integrity of the APK.
 *
 * <p>This method adds one or more errors to the {@code result} if a verification error is
 * expected to be encountered on an Android platform version in the
 * {@code [minSdkVersion, maxSdkVersion]} range.
 */
private static void parseSigner(ByteBuffer signerBlock, CertificateFactory certFactory, ApkSigningBlockUtils.Result.SignerInfo result, Set<ContentDigestAlgorithm> contentDigestsToVerify) throws ApkFormatException, NoSuchAlgorithmException {
    ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
    byte[] signedDataBytes = new byte[signedData.remaining()];
    signedData.get(signedDataBytes);
    signedData.flip();
    result.signedData = signedDataBytes;
    int parsedMinSdkVersion = signerBlock.getInt();
    int parsedMaxSdkVersion = signerBlock.getInt();
    result.minSdkVersion = parsedMinSdkVersion;
    result.maxSdkVersion = parsedMaxSdkVersion;
    if (parsedMinSdkVersion < 0 || parsedMinSdkVersion > parsedMaxSdkVersion) {
        result.addError(Issue.V3_SIG_INVALID_SDK_VERSIONS, parsedMinSdkVersion, parsedMaxSdkVersion);
    }
    ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
    byte[] publicKeyBytes = readLengthPrefixedByteArray(signerBlock);
    // Parse the signatures block and identify supported signatures
    int signatureCount = 0;
    List<ApkSigningBlockUtils.SupportedSignature> supportedSignatures = new ArrayList<>(1);
    while (signatures.hasRemaining()) {
        signatureCount++;
        try {
            ByteBuffer signature = getLengthPrefixedSlice(signatures);
            int sigAlgorithmId = signature.getInt();
            byte[] sigBytes = readLengthPrefixedByteArray(signature);
            result.signatures.add(new ApkSigningBlockUtils.Result.SignerInfo.Signature(sigAlgorithmId, sigBytes));
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.findById(sigAlgorithmId);
            if (signatureAlgorithm == null) {
                result.addWarning(Issue.V3_SIG_UNKNOWN_SIG_ALGORITHM, sigAlgorithmId);
                continue;
            }
            // TODO consider dropping deprecated signatures for v3 or modifying
            // getSignaturesToVerify (called below)
            supportedSignatures.add(new ApkSigningBlockUtils.SupportedSignature(signatureAlgorithm, sigBytes));
        } catch (ApkFormatException | BufferUnderflowException e) {
            result.addError(Issue.V3_SIG_MALFORMED_SIGNATURE, signatureCount);
            return;
        }
    }
    if (result.signatures.isEmpty()) {
        result.addError(Issue.V3_SIG_NO_SIGNATURES);
        return;
    }
    // Verify signatures over signed-data block using the public key
    List<ApkSigningBlockUtils.SupportedSignature> signaturesToVerify = null;
    try {
        signaturesToVerify = ApkSigningBlockUtils.getSignaturesToVerify(supportedSignatures, result.minSdkVersion, result.maxSdkVersion);
    } catch (ApkSigningBlockUtils.NoSupportedSignaturesException e) {
        result.addError(Issue.V3_SIG_NO_SUPPORTED_SIGNATURES);
        return;
    }
    for (ApkSigningBlockUtils.SupportedSignature signature : signaturesToVerify) {
        SignatureAlgorithm signatureAlgorithm = signature.algorithm;
        String jcaSignatureAlgorithm = signatureAlgorithm.getJcaSignatureAlgorithmAndParams().getFirst();
        AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithm.getJcaSignatureAlgorithmAndParams().getSecond();
        String keyAlgorithm = signatureAlgorithm.getJcaKeyAlgorithm();
        PublicKey publicKey;
        try {
            publicKey = KeyFactory.getInstance(keyAlgorithm).generatePublic(new X509EncodedKeySpec(publicKeyBytes));
        } catch (Exception e) {
            result.addError(Issue.V3_SIG_MALFORMED_PUBLIC_KEY, e);
            return;
        }
        try {
            Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
            sig.initVerify(publicKey);
            if (jcaSignatureAlgorithmParams != null) {
                sig.setParameter(jcaSignatureAlgorithmParams);
            }
            signedData.position(0);
            sig.update(signedData);
            byte[] sigBytes = signature.signature;
            if (!sig.verify(sigBytes)) {
                result.addError(Issue.V3_SIG_DID_NOT_VERIFY, signatureAlgorithm);
                return;
            }
            result.verifiedSignatures.put(signatureAlgorithm, sigBytes);
            contentDigestsToVerify.add(signatureAlgorithm.getContentDigestAlgorithm());
        } catch (InvalidKeyException | InvalidAlgorithmParameterException | SignatureException e) {
            result.addError(Issue.V3_SIG_VERIFY_EXCEPTION, signatureAlgorithm, e);
            return;
        }
    }
    // At least one signature over signedData has verified. We can now parse signed-data.
    signedData.position(0);
    ByteBuffer digests = getLengthPrefixedSlice(signedData);
    ByteBuffer certificates = getLengthPrefixedSlice(signedData);
    int signedMinSdkVersion = signedData.getInt();
    if (signedMinSdkVersion != parsedMinSdkVersion) {
        result.addError(Issue.V3_MIN_SDK_VERSION_MISMATCH_BETWEEN_SIGNER_AND_SIGNED_DATA_RECORD, parsedMinSdkVersion, signedMinSdkVersion);
    }
    int signedMaxSdkVersion = signedData.getInt();
    if (signedMaxSdkVersion != parsedMaxSdkVersion) {
        result.addError(Issue.V3_MAX_SDK_VERSION_MISMATCH_BETWEEN_SIGNER_AND_SIGNED_DATA_RECORD, parsedMaxSdkVersion, signedMaxSdkVersion);
    }
    ByteBuffer additionalAttributes = getLengthPrefixedSlice(signedData);
    // Parse the certificates block
    int certificateIndex = -1;
    while (certificates.hasRemaining()) {
        certificateIndex++;
        byte[] encodedCert = readLengthPrefixedByteArray(certificates);
        X509Certificate certificate;
        try {
            certificate = X509CertificateUtils.generateCertificate(encodedCert, certFactory);
        } catch (CertificateException e) {
            result.addError(Issue.V3_SIG_MALFORMED_CERTIFICATE, certificateIndex, certificateIndex + 1, e);
            return;
        }
        // Wrap the cert so that the result's getEncoded returns exactly the original encoded
        // form. Without this, getEncoded may return a different form from what was stored in
        // the signature. This is because some X509Certificate(Factory) implementations
        // re-encode certificates.
        certificate = new GuaranteedEncodedFormX509Certificate(certificate, encodedCert);
        result.certs.add(certificate);
    }
    if (result.certs.isEmpty()) {
        result.addError(Issue.V3_SIG_NO_CERTIFICATES);
        return;
    }
    X509Certificate mainCertificate = result.certs.get(0);
    byte[] certificatePublicKeyBytes;
    try {
        certificatePublicKeyBytes = ApkSigningBlockUtils.encodePublicKey(mainCertificate.getPublicKey());
    } catch (InvalidKeyException e) {
        System.out.println("Caught an exception encoding the public key: " + e);
        e.printStackTrace();
        certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
    }
    if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
        result.addError(Issue.V3_SIG_PUBLIC_KEY_MISMATCH_BETWEEN_CERTIFICATE_AND_SIGNATURES_RECORD, ApkSigningBlockUtils.toHex(certificatePublicKeyBytes), ApkSigningBlockUtils.toHex(publicKeyBytes));
        return;
    }
    // Parse the digests block
    int digestCount = 0;
    while (digests.hasRemaining()) {
        digestCount++;
        try {
            ByteBuffer digest = getLengthPrefixedSlice(digests);
            int sigAlgorithmId = digest.getInt();
            byte[] digestBytes = readLengthPrefixedByteArray(digest);
            result.contentDigests.add(new ApkSigningBlockUtils.Result.SignerInfo.ContentDigest(sigAlgorithmId, digestBytes));
        } catch (ApkFormatException | BufferUnderflowException e) {
            result.addError(Issue.V3_SIG_MALFORMED_DIGEST, digestCount);
            return;
        }
    }
    List<Integer> sigAlgsFromSignaturesRecord = new ArrayList<>(result.signatures.size());
    for (ApkSigningBlockUtils.Result.SignerInfo.Signature signature : result.signatures) {
        sigAlgsFromSignaturesRecord.add(signature.getAlgorithmId());
    }
    List<Integer> sigAlgsFromDigestsRecord = new ArrayList<>(result.contentDigests.size());
    for (ApkSigningBlockUtils.Result.SignerInfo.ContentDigest digest : result.contentDigests) {
        sigAlgsFromDigestsRecord.add(digest.getSignatureAlgorithmId());
    }
    if (!sigAlgsFromSignaturesRecord.equals(sigAlgsFromDigestsRecord)) {
        result.addError(Issue.V3_SIG_SIG_ALG_MISMATCH_BETWEEN_SIGNATURES_AND_DIGESTS_RECORDS, sigAlgsFromSignaturesRecord, sigAlgsFromDigestsRecord);
        return;
    }
    // Parse the additional attributes block.
    int additionalAttributeCount = 0;
    while (additionalAttributes.hasRemaining()) {
        additionalAttributeCount++;
        try {
            ByteBuffer attribute = getLengthPrefixedSlice(additionalAttributes);
            int id = attribute.getInt();
            byte[] value = ByteBufferUtils.toByteArray(attribute);
            result.additionalAttributes.add(new ApkSigningBlockUtils.Result.SignerInfo.AdditionalAttribute(id, value));
            if (id == V3SchemeConstants.PROOF_OF_ROTATION_ATTR_ID) {
                try {
                    // SigningCertificateLineage is verified when built
                    result.signingCertificateLineage = SigningCertificateLineage.readFromV3AttributeValue(value);
                    // make sure that the last cert in the chain matches this signer cert
                    SigningCertificateLineage subLineage = result.signingCertificateLineage.getSubLineage(result.certs.get(0));
                    if (result.signingCertificateLineage.size() != subLineage.size()) {
                        result.addError(Issue.V3_SIG_POR_CERT_MISMATCH);
                    }
                } catch (SecurityException e) {
                    result.addError(Issue.V3_SIG_POR_DID_NOT_VERIFY);
                } catch (IllegalArgumentException e) {
                    result.addError(Issue.V3_SIG_POR_CERT_MISMATCH);
                } catch (Exception e) {
                    result.addError(Issue.V3_SIG_MALFORMED_LINEAGE);
                }
            } else {
                result.addWarning(Issue.V3_SIG_UNKNOWN_ADDITIONAL_ATTRIBUTE, id);
            }
        } catch (ApkFormatException | BufferUnderflowException e) {
            result.addError(Issue.V3_SIG_MALFORMED_ADDITIONAL_ATTRIBUTE, additionalAttributeCount);
            return;
        }
    }
}
Also used : GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) ArrayList(java.util.ArrayList) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm) CertificateException(java.security.cert.CertificateException) SignatureException(java.security.SignatureException) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) ApkFormatException(com.android.apksig.apk.ApkFormatException) BufferUnderflowException(java.nio.BufferUnderflowException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) PublicKey(java.security.PublicKey) X509EncodedKeySpec(java.security.spec.X509EncodedKeySpec) InvalidKeyException(java.security.InvalidKeyException) ByteBuffer(java.nio.ByteBuffer) SignatureNotFoundException(com.android.apksig.internal.apk.ApkSigningBlockUtils.SignatureNotFoundException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) ApkFormatException(com.android.apksig.apk.ApkFormatException) SignatureException(java.security.SignatureException) IOException(java.io.IOException) CertificateException(java.security.cert.CertificateException) BufferUnderflowException(java.nio.BufferUnderflowException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) X509Certificate(java.security.cert.X509Certificate) GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) SigningCertificateLineage(com.android.apksig.SigningCertificateLineage) Signature(java.security.Signature) AlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec)

Example 5 with SigningCertificateLineage

use of com.android.apksig.SigningCertificateLineage in project bundletool by google.

the class BuildApksCommandTest method populateLineage_binaryFile.

@Test
public void populateLineage_binaryFile() throws Exception {
    SigningCertificateLineage.SignerConfig signerConfig = new SigningCertificateLineage.SignerConfig.Builder(privateKey, certificate).build();
    SigningCertificateLineage.SignerConfig oldestSignerConfig = new SigningCertificateLineage.SignerConfig.Builder(oldestSignerPrivateKey, oldestSignerCertificate).build();
    SigningCertificateLineage lineage = new SigningCertificateLineage.Builder(oldestSignerConfig, signerConfig).build();
    File lineageFile = tmpDir.resolve("lineage-file").toFile();
    lineage.writeToFile(lineageFile);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    BuildApksCommand commandViaFlags = BuildApksCommand.fromFlags(new FlagParser().parse("--bundle=" + bundlePath, "--output=" + outputFilePath, "--aapt2=" + AAPT2_PATH, "--ks=" + keystorePath, "--ks-key-alias=" + KEY_ALIAS, "--ks-pass=pass:" + KEYSTORE_PASSWORD, "--key-pass=pass:" + KEY_PASSWORD, "--lineage=" + lineageFile, "--oldest-signer=" + oldestSignerPropertiesPath), new PrintStream(output), systemEnvironmentProvider, fakeAdbServer);
    SigningConfiguration signingConfiguration = commandViaFlags.getSigningConfiguration().get();
    assertThat(signingConfiguration.getSigningCertificateLineage().get().getCertificatesInLineage()).containsExactly(oldestSignerCertificate, certificate);
    assertThat(signingConfiguration.getOldestSigner().get().getPrivateKey()).isEqualTo(oldestSignerConfig.getPrivateKey());
    assertThat(signingConfiguration.getOldestSigner().get().getCertificates()).containsExactly(oldestSignerConfig.getCertificate());
}
Also used : PrintStream(java.io.PrintStream) SigningCertificateLineage(com.android.apksig.SigningCertificateLineage) ApksigSigningConfiguration(com.android.tools.build.bundletool.model.ApksigSigningConfiguration) SigningConfiguration(com.android.tools.build.bundletool.model.SigningConfiguration) SignerConfig(com.android.tools.build.bundletool.model.SignerConfig) ByteArrayOutputStream(java.io.ByteArrayOutputStream) FlagParser(com.android.tools.build.bundletool.flags.FlagParser) DeviceFactory.createDeviceSpecFile(com.android.tools.build.bundletool.testing.DeviceFactory.createDeviceSpecFile) File(java.io.File) CodeRelatedFile(com.android.bundle.CodeTransparencyOuterClass.CodeRelatedFile) Test(org.junit.Test)

Aggregations

SigningCertificateLineage (com.android.apksig.SigningCertificateLineage)7 File (java.io.File)6 ArrayList (java.util.ArrayList)5 RandomAccessFile (java.io.RandomAccessFile)3 X509Certificate (java.security.cert.X509Certificate)3 ApkFormatException (com.android.apksig.apk.ApkFormatException)2 CodeRelatedFile (com.android.bundle.CodeTransparencyOuterClass.CodeRelatedFile)2 FlagParser (com.android.tools.build.bundletool.flags.FlagParser)2 ApksigSigningConfiguration (com.android.tools.build.bundletool.model.ApksigSigningConfiguration)2 SignerConfig (com.android.tools.build.bundletool.model.SignerConfig)2 SigningConfiguration (com.android.tools.build.bundletool.model.SigningConfiguration)2 DeviceFactory.createDeviceSpecFile (com.android.tools.build.bundletool.testing.DeviceFactory.createDeviceSpecFile)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 IOException (java.io.IOException)2 PrintStream (java.io.PrintStream)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 Test (org.junit.Test)2 Signature (android.content.pm.Signature)1 WorkerThread (androidx.annotation.WorkerThread)1 ApkSigner (com.android.apksig.ApkSigner)1