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);
}
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());
}
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");
}
}
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;
}
}
}
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());
}
Aggregations