Allow generating source stamp in apksig locally am: 530fd3ea8c
Change-Id: I2c241c0c9f3b837b219d07296adb6ff1fc429640
diff --git a/src/apksigner/java/com/android/apksigner/ApkSignerTool.java b/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
index f864595..d2f8a1b 100644
--- a/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
+++ b/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
@@ -128,6 +128,7 @@
int maxSdkVersion = Integer.MAX_VALUE;
List<SignerParams> signers = new ArrayList<>(1);
SignerParams signerParams = new SignerParams();
+ SignerParams sourceStampSignerParams = new SignerParams();
SigningCertificateLineage lineage = null;
List<ProviderInstallSpec> providers = new ArrayList<>();
ProviderInstallSpec providerParams = new ProviderInstallSpec();
@@ -135,6 +136,7 @@
String optionName;
String optionOriginalForm = null;
boolean v4SigningFlagFound = false;
+ boolean sourceStampFlagFound = false;
while ((optionName = optionsParser.nextOption()) != null) {
optionOriginalForm = optionsParser.getOptionOriginalForm();
if (("help".equals(optionName)) || ("h".equals(optionName))) {
@@ -224,6 +226,9 @@
} 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 {
throw new ParameterException(
"Unsupported option: " + optionOriginalForm + ". See --help for supported"
@@ -280,49 +285,27 @@
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);
- try {
- signer.loadPrivateKeyAndCerts(passwordRetriever);
- } catch (ParameterException e) {
- System.err.println(
- "Failed to load signer \"" + signer.getName() + "\": "
- + e.getMessage());
- System.exit(2);
- return;
- } catch (Exception e) {
- System.err.println("Failed to load signer \"" + signer.getName() + "\"");
- e.printStackTrace();
- System.exit(2);
+ ApkSigner.SignerConfig signerConfig = getSignerConfig(signer, passwordRetriever);
+ if (signerConfig == null) {
return;
}
- String v1SigBasename;
- if (signer.getV1SigFileBasename() != null) {
- v1SigBasename = signer.getV1SigFileBasename();
- } else if (signer.getKeystoreKeyAlias() != null) {
- v1SigBasename = signer.getKeystoreKeyAlias();
- } else if (signer.getKeyFile() != null) {
- String keyFileName = new File(signer.getKeyFile()).getName();
- int delimiterIndex = keyFileName.indexOf('.');
- if (delimiterIndex == -1) {
- v1SigBasename = keyFileName;
- } else {
- v1SigBasename = keyFileName.substring(0, delimiterIndex);
- }
- } else {
- throw new RuntimeException(
- "Neither KeyStore key alias nor private key file available");
- }
- ApkSigner.SignerConfig signerConfig =
- new ApkSigner.SignerConfig.Builder(
- v1SigBasename, signer.getPrivateKey(), signer.getCerts())
- .build();
signerConfigs.add(signerConfig);
}
+ if (sourceStampFlagFound) {
+ sourceStampSignerParams.setName("stamp signer");
+ sourceStampSignerConfig =
+ getSignerConfig(sourceStampSignerParams, passwordRetriever);
+ if (sourceStampSignerConfig == null) {
+ return;
+ }
+ }
}
if (outputApk == null) {
@@ -355,6 +338,9 @@
Files.deleteIfExists(outputV4SignatureFile.toPath());
apkSignerBuilder.setV4SignatureOutputFile(outputV4SignatureFile);
}
+ if (sourceStampSignerConfig != null) {
+ apkSignerBuilder.setSourceStampSignerConfig(sourceStampSignerConfig);
+ }
ApkSigner apkSigner = apkSignerBuilder.build();
try {
apkSigner.sign();
@@ -378,6 +364,44 @@
}
}
+ private static ApkSigner.SignerConfig getSignerConfig(
+ SignerParams signer, PasswordRetriever passwordRetriever) {
+ try {
+ signer.loadPrivateKeyAndCerts(passwordRetriever);
+ } catch (ParameterException e) {
+ System.err.println(
+ "Failed to load signer \"" + signer.getName() + "\": " + e.getMessage());
+ System.exit(2);
+ return null;
+ } catch (Exception e) {
+ System.err.println("Failed to load signer \"" + signer.getName() + "\"");
+ e.printStackTrace();
+ System.exit(2);
+ return null;
+ }
+ String v1SigBasename;
+ if (signer.getV1SigFileBasename() != null) {
+ v1SigBasename = signer.getV1SigFileBasename();
+ } else if (signer.getKeystoreKeyAlias() != null) {
+ v1SigBasename = signer.getKeystoreKeyAlias();
+ } else if (signer.getKeyFile() != null) {
+ String keyFileName = new File(signer.getKeyFile()).getName();
+ int delimiterIndex = keyFileName.indexOf('.');
+ if (delimiterIndex == -1) {
+ v1SigBasename = keyFileName;
+ } else {
+ v1SigBasename = keyFileName.substring(0, delimiterIndex);
+ }
+ } else {
+ throw new RuntimeException("Neither KeyStore key alias nor private key file available");
+ }
+ ApkSigner.SignerConfig signerConfig =
+ new ApkSigner.SignerConfig.Builder(
+ v1SigBasename, signer.getPrivateKey(), signer.getCerts())
+ .build();
+ return signerConfig;
+ }
+
private static void verify(String[] params) throws Exception {
if (params.length == 0) {
printUsage(HELP_PAGE_VERIFY);
@@ -500,6 +524,7 @@
System.out.println(
"Verified using v4 scheme (APK Signature Scheme v4): "
+ result.isVerifiedUsingV4Scheme());
+ System.out.println("Verified for SourceStamp: " + result.isSourceStampVerified());
System.out.println("Number of signers: " + signerCerts.size());
}
if (printCerts) {
@@ -558,6 +583,14 @@
}
}
+ ApkVerifier.Result.SourceStampInfo sourceStampInfo = result.getSourceStampInfo();
+ for (ApkVerifier.IssueWithParams error : sourceStampInfo.getErrors()) {
+ System.err.println("ERROR: SourceStamp: " + error);
+ }
+ for (ApkVerifier.IssueWithParams warning : sourceStampInfo.getWarnings()) {
+ warningsOut.println("WARNING: SourceStamp: " + warning);
+ }
+
if (!verified) {
System.exit(1);
return;
diff --git a/src/apksigner/java/com/android/apksigner/help_sign.txt b/src/apksigner/java/com/android/apksigner/help_sign.txt
index b9d0146..5efd952 100644
--- a/src/apksigner/java/com/android/apksigner/help_sign.txt
+++ b/src/apksigner/java/com/android/apksigner/help_sign.txt
@@ -91,6 +91,9 @@
(aka v1 scheme) signature of this signer. By default,
KeyStore key alias or basename of key file is used.
+--stamp-signer The signing information for the signer of the source stamp
+ to be included in the APK.
+
PER-SIGNER SIGNING KEY & CERTIFICATE OPTIONS
There are two ways to provide the signer's private key and certificate: (1) Java
KeyStore (see --ks), or (2) private key file in PKCS #8 format and certificate