use of com.android.bundle.CodeTransparencyOuterClass.CodeTransparency in project bundletool by google.
the class AddTransparencyCommandTest method execute_defaultMode_success.
@Test
public void execute_defaultMode_success() throws Exception {
createBundle(bundlePath);
AddTransparencyCommand addTransparencyCommand = AddTransparencyCommand.builder().setMode(Mode.DEFAULT).setBundlePath(bundlePath).setOutputPath(outputBundlePath).setSignerConfig(signerConfig).build();
addTransparencyCommand.execute();
AppBundle outputBundle = AppBundle.buildFromZip(new ZipFile(outputBundlePath.toFile()));
Optional<ByteSource> signedTransparencyFile = outputBundle.getBundleMetadata().getFileAsByteSource(BUNDLETOOL_NAMESPACE, BundleMetadata.TRANSPARENCY_SIGNED_FILE_NAME);
assertThat(signedTransparencyFile).isPresent();
JsonWebSignature jws = (JsonWebSignature) JsonWebSignature.fromCompactSerialization(signedTransparencyFile.get().asCharSource(Charset.defaultCharset()).read());
assertThat(jws.getAlgorithmHeaderValue()).isEqualTo(RSA_USING_SHA256);
assertThat(jws.getCertificateChainHeaderValue()).isEqualTo(signerConfig.getCertificates());
// jws.getPayload method will do signature verification using the public key set below.
jws.setKey(signerConfig.getCertificates().get(0).getPublicKey());
CodeTransparency transparencyProto = getTransparencyProto(jws.getPayload());
assertThat(transparencyProto).isEqualTo(expectedTransparencyProto());
}
use of com.android.bundle.CodeTransparencyOuterClass.CodeTransparency in project bundletool by google.
the class AddTransparencyCommandTest method execute_injectSignature.
@Test
public void execute_injectSignature() throws Exception {
// create bundle.
createBundle(bundlePath);
// add transparency file in default mode.
Path tmpOutputBundlePath = tmpDir.resolve("tmp_output_bundle.aab");
AddTransparencyCommand.builder().setMode(Mode.DEFAULT).setBundlePath(bundlePath).setOutputPath(tmpOutputBundlePath).setSignerConfig(signerConfig).build().execute();
// get the correct transparency signature bytes.
AppBundle tmpOutputBundle = AppBundle.buildFromZip(new ZipFile(tmpOutputBundlePath.toFile()));
ByteSource signedTransparencyFile = tmpOutputBundle.getBundleMetadata().getFileAsByteSource(BUNDLETOOL_NAMESPACE, BundleMetadata.TRANSPARENCY_SIGNED_FILE_NAME).get();
String jws = signedTransparencyFile.asCharSource(Charset.defaultCharset()).read();
String signature = ImmutableList.copyOf(Splitter.on(".").split(jws)).get(2);
byte[] signatureBytes = BaseEncoding.base64Url().decode(signature);
Files.write(transparencySignatureFilePath, signatureBytes);
// inject signature into the original bundle
AddTransparencyCommand.builder().setMode(Mode.INJECT_SIGNATURE).setBundlePath(bundlePath).setOutputPath(outputBundlePath).setTransparencyKeyCertificate(signerConfig.getCertificates().get(0)).setTransparencySignaturePath(transparencySignatureFilePath).build().execute();
// verify that the output bundle contains signed code transparency metadata.
AppBundle outputBundle = AppBundle.buildFromZip(new ZipFile(outputBundlePath.toFile()));
Optional<ByteSource> finalSignedTransparencyFile = outputBundle.getBundleMetadata().getFileAsByteSource(BUNDLETOOL_NAMESPACE, BundleMetadata.TRANSPARENCY_SIGNED_FILE_NAME);
assertThat(finalSignedTransparencyFile).isPresent();
JsonWebSignature finalJws = (JsonWebSignature) JsonWebSignature.fromCompactSerialization(finalSignedTransparencyFile.get().asCharSource(Charset.defaultCharset()).read());
assertThat(finalJws.getAlgorithmHeaderValue()).isEqualTo(RSA_USING_SHA256);
assertThat(finalJws.getCertificateChainHeaderValue()).isEqualTo(signerConfig.getCertificates());
// jws.getPayload method will do signature verification using the public key set below.
finalJws.setKey(signerConfig.getCertificates().get(0).getPublicKey());
CodeTransparency transparencyProto = getTransparencyProto(finalJws.getPayload());
assertThat(transparencyProto).isEqualTo(expectedTransparencyProto());
}
use of com.android.bundle.CodeTransparencyOuterClass.CodeTransparency in project bundletool by google.
the class BundleTransparencyCheckUtils method checkTransparency.
/**
* Verifies code transparency for the given bundle, and returns {@link TransparencyCheckResult}.
*
* @throws InvalidBundleException if an error occurs during verification.
*/
public static TransparencyCheckResult checkTransparency(AppBundle bundle, ByteSource signedTransparencyFile) {
if (bundle.hasSharedUserId()) {
throw InvalidBundleException.builder().withUserMessage("Transparency file is present in the bundle, but it can not be verified because" + " `sharedUserId` attribute is specified in one of the manifests.").build();
}
TransparencyCheckResult.Builder result = TransparencyCheckResult.builder();
JsonWebSignature jws = CodeTransparencyCryptoUtils.parseJws(signedTransparencyFile);
if (!CodeTransparencyCryptoUtils.verifySignature(jws)) {
return result.errorMessage("Verification failed because code transparency signature is invalid.").build();
}
result.transparencySignatureVerified(true).transparencyKeyCertificateFingerprint(CodeTransparencyCryptoUtils.getCertificateFingerprint(jws));
CodeTransparency parsedTransparencyFile = CodeTransparencyFactory.parseFrom(jws.getUnverifiedPayload());
CodeTransparencyVersion.checkVersion(parsedTransparencyFile);
MapDifference<String, CodeRelatedFile> difference = Maps.difference(getCodeRelatedFilesFromParsedTransparencyFile(parsedTransparencyFile), getCodeRelatedFilesFromBundle(bundle));
result.fileContentsVerified(difference.areEqual());
if (!difference.areEqual()) {
result.errorMessage(getDiffAsString(difference));
}
return result.build();
}
use of com.android.bundle.CodeTransparencyOuterClass.CodeTransparency in project bundletool by google.
the class BuildApksManagerTest method transparencyFilePropagatedAsExpected.
@Test
public void transparencyFilePropagatedAsExpected() throws Exception {
String dexFilePath = "dex/classes.dex";
byte[] dexFileInBaseModuleContent = TestData.readBytes("testdata/dex/classes.dex");
byte[] dexFileInFeatureModuleContent = TestData.readBytes("testdata/dex/classes-other.dex");
String libFilePath = "lib/x86_64/libsome.so";
byte[] libFileInBaseModuleContent = new byte[] { 4, 5, 6 };
CodeTransparency codeTransparency = CodeTransparency.newBuilder().addCodeRelatedFile(CodeRelatedFile.newBuilder().setType(CodeRelatedFile.Type.DEX).setPath("base/" + dexFilePath).setSha256(ByteSource.wrap(dexFileInBaseModuleContent).hash(Hashing.sha256()).toString())).addCodeRelatedFile(CodeRelatedFile.newBuilder().setType(CodeRelatedFile.Type.NATIVE_LIBRARY).setPath("base/" + libFilePath).setSha256(ByteSource.wrap(libFileInBaseModuleContent).hash(Hashing.sha256()).toString()).setApkPath(libFilePath)).addCodeRelatedFile(CodeRelatedFile.newBuilder().setType(CodeRelatedFile.Type.DEX).setPath("feature/" + dexFilePath).setSha256(ByteSource.wrap(dexFileInFeatureModuleContent).hash(Hashing.sha256()).toString())).build();
Path bundlePath = tmpDir.resolve("bundle.aab");
AppBundleBuilder appBundle = new AppBundleBuilder().addModule("base", module -> module.setManifest(androidManifest("com.test.app", withMinSdkVersion(20))).setResourceTable(resourceTableWithTestLabel("Test feature")).addFile(dexFilePath, bundlePath, ZipPath.create("base/" + dexFilePath), dexFileInBaseModuleContent).addFile(libFilePath, bundlePath, ZipPath.create("base/" + libFilePath), libFileInBaseModuleContent).setNativeConfig(nativeLibraries(targetedNativeDirectory("lib/x86_64", nativeDirectoryTargeting(AbiAlias.X86_64))))).addModule("feature", module -> module.setManifest(androidManifest("com.test.app", withDelivery(DeliveryType.ON_DEMAND), withFusingAttribute(true), withTitle("@string/test_label", TEST_LABEL_RESOURCE_ID))).addFile(dexFilePath, bundlePath, ZipPath.create("feature/" + dexFilePath), dexFileInFeatureModuleContent)).addMetadataFile(BundleMetadata.BUNDLETOOL_NAMESPACE, BundleMetadata.TRANSPARENCY_SIGNED_FILE_NAME, CharSource.wrap(createJwsToken(codeTransparency, certificate, privateKey)).asByteSource(Charset.defaultCharset()));
TestComponent.useTestModule(this, createTestModuleBuilder().withOutputPath(outputFilePath).withAppBundle(appBundle.build()).build());
buildApksManager.execute();
ZipFile apkSetFile = openZipFile(outputFilePath.toFile());
BuildApksResult result = extractTocFromApkSetFile(apkSetFile, outputDir);
ImmutableList<ApkDescription> splitApks = apkDescriptions(splitApkVariants(result));
// Transparency file should be propagated to main split of the base module.
ImmutableList<ApkDescription> mainSplitsOfBaseModule = splitApks.stream().filter(apk -> apk.getSplitApkMetadata().getSplitId().isEmpty() && apk.getSplitApkMetadata().getIsMasterSplit()).collect(toImmutableList());
assertThat(mainSplitsOfBaseModule).hasSize(2);
for (ApkDescription apk : mainSplitsOfBaseModule) {
ZipFile zipFile = openZipFile(extractFromApkSetFile(apkSetFile, apk.getPath(), outputDir));
assertThat(filesUnderPath(zipFile, ZipPath.create("META-INF"))).contains("META-INF/" + BundleMetadata.TRANSPARENCY_SIGNED_FILE_NAME);
}
// Other splits should not contain transparency file.
ImmutableList<ApkDescription> otherSplits = splitApks.stream().filter(apk -> !apk.getSplitApkMetadata().getSplitId().isEmpty()).collect(toImmutableList());
assertThat(otherSplits).hasSize(4);
for (ApkDescription apk : otherSplits) {
ZipFile zipFile = openZipFile(extractFromApkSetFile(apkSetFile, apk.getPath(), outputDir));
assertThat(filesUnderPath(zipFile, ZipPath.create("META-INF"))).isEmpty();
}
// Because minSdkVersion < 21, bundle has a feature module and merging strategy is
// MERGE_IF_NEEDED (default), transparency file should not be propagated to standalone APK.
assertThat(standaloneApkVariants(result)).hasSize(1);
ImmutableList<ApkDescription> standaloneApks = apkDescriptions(standaloneApkVariants(result).get(0));
File standaloneApkFile = extractFromApkSetFile(apkSetFile, standaloneApks.get(0).getPath(), outputDir);
ZipFile standaloneApkZip = openZipFile(standaloneApkFile);
assertThat(filesUnderPath(standaloneApkZip, ZipPath.create("META-INF"))).isEmpty();
}
use of com.android.bundle.CodeTransparencyOuterClass.CodeTransparency in project bundletool by google.
the class CodeTransparencyValidatorTest method createBundle.
private void createBundle(Path path, CodeTransparency codeTransparency) throws Exception {
String transparencyPayload = JsonFormat.printer().print(codeTransparency);
AppBundleBuilder appBundle = new AppBundleBuilder().addModule("base", module -> module.setManifest(androidManifest("com.test.app")).addFile(DEX_PATH, DEX_FILE_CONTENT).addFile(NATIVE_LIB_PATH, NATIVE_LIB_FILE_CONTENT)).addMetadataFile(BundleMetadata.BUNDLETOOL_NAMESPACE, BundleMetadata.TRANSPARENCY_SIGNED_FILE_NAME, CharSource.wrap(createJwsToken(transparencyPayload)).asByteSource(Charset.defaultCharset()));
new AppBundleSerializer().writeToDisk(appBundle.build(), path);
}
Aggregations