Snap for 6439596 from 83eec36412695949f24be9d917ed7ba26fff3f5c to qt-aml-tzdata-release
Change-Id: I4ca13275f341d48b2c034e427f6ef846b89bf392
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..7e39c8e
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,48 @@
+# Bazel (https://bazel.io/) BUILD file for apksig library and apksigner tool.
+
+licenses(["notice"]) # Apache License 2.0
+
+# Public API of the apksig library
+java_library(
+ name = "apksig",
+ srcs = glob(
+ ["src/main/java/**/*.java"],
+ exclude = ["src/main/java/com/android/apksig/internal/**/*.java"],
+ ),
+ visibility = ["//visibility:public"],
+ deps = [":apksig-all"],
+)
+
+# All of apksig library, including private API which clients must not directly depend on. Private
+# API may change without regard to its clients outside of the apksig project.
+java_library(
+ name = "apksig-all",
+ srcs = glob(["src/main/java/**/*.java"]),
+ visibility = ["//visibility:private"],
+)
+
+java_binary(
+ name = "apksigner",
+ srcs = glob([
+ "src/apksigner/java/**/*.java",
+ ]),
+ main_class = "com.android.apksigner.ApkSignerTool",
+ resources = glob([
+ "src/apksigner/java/**/*.txt",
+ ]),
+ visibility = ["//visibility:public"],
+ deps = [":apksig"],
+)
+
+java_test(
+ name = "all",
+ srcs = glob([
+ "src/test/java/com/android/apksig/**/*.java",
+ ]),
+ resources = glob([
+ "src/test/resources/**/*",
+ ]),
+ size = "small",
+ test_class = "com.android.apksig.AllTests",
+ deps = [":apksig-all"],
+)
diff --git a/src/main/java/com/android/apksig/ApkSigner.java b/src/main/java/com/android/apksig/ApkSigner.java
index e3870e7..88f2617 100644
--- a/src/main/java/com/android/apksig/ApkSigner.java
+++ b/src/main/java/com/android/apksig/ApkSigner.java
@@ -240,8 +240,7 @@
List<CentralDirectoryRecord> inputCdRecords =
parseZipCentralDirectory(inputCd, inputZipSections);
- List<Hints.PatternWithRange> pinPatterns = extractPinPatterns(
- inputCdRecords, inputApkLfhSection);
+ List<Pattern> pinPatterns = extractPinPatterns(inputCdRecords, inputApkLfhSection);
List<Hints.ByteRange> pinByteRanges = pinPatterns == null ? null : new ArrayList<>();
// Step 3. Obtain a signer engine instance
@@ -372,33 +371,28 @@
// Output entry's Local File Header + data
long outputLocalFileHeaderOffset = outputOffset;
- OutputSizeAndDataOffset outputLfrResult =
+ long outputLocalFileRecordSize =
outputInputJarEntryLfhRecordPreservingDataAlignment(
inputApkLfhSection,
inputLocalFileRecord,
outputApkOut,
outputLocalFileHeaderOffset);
- outputOffset += outputLfrResult.outputBytes;
- long outputDataOffset =
- outputLocalFileHeaderOffset + outputLfrResult.dataOffsetBytes;
+ outputOffset += outputLocalFileRecordSize;
if (pinPatterns != null) {
- boolean pinFileHeader = false;
- for (Hints.PatternWithRange pinPattern : pinPatterns) {
+ boolean pinThisFile = false;
+ for (Pattern pinPattern : pinPatterns) {
if (pinPattern.matcher(inputCdRecord.getName()).matches()) {
- Hints.ByteRange dataRange =
- new Hints.ByteRange(outputDataOffset, outputOffset);
- Hints.ByteRange pinRange =
- pinPattern.ClampToAbsoluteByteRange(dataRange);
- if (pinRange != null) {
- pinFileHeader = true;
- pinByteRanges.add(pinRange);
- }
+ pinThisFile = true;
+ break;
}
}
- if (pinFileHeader) {
- pinByteRanges.add(new Hints.ByteRange(outputLocalFileHeaderOffset,
- outputDataOffset));
+
+ if (pinThisFile) {
+ pinByteRanges.add(
+ new Hints.ByteRange(
+ outputLocalFileHeaderOffset,
+ outputOffset));
}
}
@@ -580,17 +574,7 @@
inspectEntryRequest.done();
}
- private static class OutputSizeAndDataOffset {
- public long outputBytes;
- public long dataOffsetBytes;
-
- public OutputSizeAndDataOffset(long outputBytes, long dataOffsetBytes) {
- this.outputBytes = outputBytes;
- this.dataOffsetBytes = dataOffsetBytes;
- }
- }
-
- private static OutputSizeAndDataOffset outputInputJarEntryLfhRecordPreservingDataAlignment(
+ private static long outputInputJarEntryLfhRecordPreservingDataAlignment(
DataSource inputLfhSection,
LocalFileRecord inputRecord,
DataSink outputLfhSection,
@@ -598,27 +582,21 @@
long inputOffset = inputRecord.getStartOffsetInArchive();
if (inputOffset == outputOffset) {
// This record's data will be aligned same as in the input APK.
- return new OutputSizeAndDataOffset(
- inputRecord.outputRecord(inputLfhSection, outputLfhSection),
- inputRecord.getDataStartOffsetInRecord());
+ return inputRecord.outputRecord(inputLfhSection, outputLfhSection);
}
int dataAlignmentMultiple = getInputJarEntryDataAlignmentMultiple(inputRecord);
if ((dataAlignmentMultiple <= 1)
|| ((inputOffset % dataAlignmentMultiple)
== (outputOffset % dataAlignmentMultiple))) {
// This record's data will be aligned same as in the input APK.
- return new OutputSizeAndDataOffset(
- inputRecord.outputRecord(inputLfhSection, outputLfhSection),
- inputRecord.getDataStartOffsetInRecord());
+ return inputRecord.outputRecord(inputLfhSection, outputLfhSection);
}
long inputDataStartOffset = inputOffset + inputRecord.getDataStartOffsetInRecord();
if ((inputDataStartOffset % dataAlignmentMultiple) != 0) {
// This record's data is not aligned in the input APK. No need to align it in the
// output.
- return new OutputSizeAndDataOffset(
- inputRecord.outputRecord(inputLfhSection, outputLfhSection),
- inputRecord.getDataStartOffsetInRecord());
+ return inputRecord.outputRecord(inputLfhSection, outputLfhSection);
}
// This record's data needs to be re-aligned in the output. This is achieved using the
@@ -628,11 +606,8 @@
inputRecord.getExtra(),
outputOffset + inputRecord.getExtraFieldStartOffsetInsideRecord(),
dataAlignmentMultiple);
- long dataOffset = inputRecord.getDataStartOffsetInRecord() +
- aligningExtra.remaining() -
- inputRecord.getExtra().remaining();
- return new OutputSizeAndDataOffset(inputRecord.outputRecordWithModifiedExtra(
- inputLfhSection, aligningExtra, outputLfhSection), dataOffset);
+ return inputRecord.outputRecordWithModifiedExtra(
+ inputLfhSection, aligningExtra, outputLfhSection);
}
private static int getInputJarEntryDataAlignmentMultiple(LocalFileRecord entry) {
@@ -819,12 +794,12 @@
* Return list of pin patterns embedded in the pin pattern asset
* file. If no such file, return {@code null}.
*/
- private static List<Hints.PatternWithRange> extractPinPatterns(
+ private static List<Pattern> extractPinPatterns(
List<CentralDirectoryRecord> cdRecords, DataSource lhfSection)
throws IOException, ApkFormatException {
CentralDirectoryRecord pinListCdRecord =
findCdRecord(cdRecords, Hints.PIN_HINT_ASSET_ZIP_ENTRY_NAME);
- List<Hints.PatternWithRange> pinPatterns = null;
+ List<Pattern> pinPatterns = null;
if (pinListCdRecord != null) {
pinPatterns = new ArrayList<>();
byte[] patternBlob;
diff --git a/src/main/java/com/android/apksig/Hints.java b/src/main/java/com/android/apksig/Hints.java
index 4070fa2..49ef2b0 100644
--- a/src/main/java/com/android/apksig/Hints.java
+++ b/src/main/java/com/android/apksig/Hints.java
@@ -20,7 +20,6 @@
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Hints {
@@ -48,39 +47,6 @@
}
}
- public static final class PatternWithRange {
- final Pattern pattern;
- final long offset;
- final long size;
-
- public PatternWithRange(String pattern) {
- this.pattern = Pattern.compile(pattern);
- this.offset= 0;
- this.size = Long.MAX_VALUE;
- }
-
- public PatternWithRange(String pattern, long offset, long size) {
- this.pattern = Pattern.compile(pattern);
- this.offset = offset;
- this.size = size;
- }
-
- public Matcher matcher(CharSequence input) {
- return this.pattern.matcher(input);
- }
-
- public ByteRange ClampToAbsoluteByteRange(ByteRange rangeIn) {
- if (rangeIn.end - rangeIn.start < this.offset) {
- return null;
- }
- long rangeOutStart = rangeIn.start + this.offset;
- long rangeOutSize = Math.min(rangeIn.end - rangeOutStart,
- this.size);
- return new ByteRange(rangeOutStart,
- rangeOutStart + rangeOutSize);
- }
- }
-
/**
* Create a blob of bytes that PinnerService understands as a
* sequence of byte ranges to pin.
@@ -99,20 +65,13 @@
return bos.toByteArray();
}
- public static ArrayList<PatternWithRange> parsePinPatterns(byte[] patternBlob) {
- ArrayList<PatternWithRange> pinPatterns = new ArrayList<>();
+ public static ArrayList<Pattern> parsePinPatterns(byte[] patternBlob) {
+ ArrayList<Pattern> pinPatterns = new ArrayList<>();
try {
for (String rawLine : new String(patternBlob, "UTF-8").split("\n")) {
String line = rawLine.replaceFirst("#.*", ""); // # starts a comment
- String[] fields = line.split(" ");
- if (fields.length == 1) {
- pinPatterns.add(new PatternWithRange(fields[0]));
- } else if (fields.length == 3) {
- long start = Long.parseLong(fields[1]);
- long end = Long.parseLong(fields[2]);
- pinPatterns.add(new PatternWithRange(fields[0], start, end - start));
- } else {
- throw new AssertionError("bad pin pattern line " + line);
+ if (!("".equals(line))) {
+ pinPatterns.add(Pattern.compile(line));
}
}
} catch (UnsupportedEncodingException ex) {
diff --git a/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java b/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
index 7c13586..cc69af3 100644
--- a/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
+++ b/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
@@ -21,16 +21,10 @@
import com.android.apksig.apk.ApkFormatException;
import com.android.apksig.apk.ApkSigningBlockNotFoundException;
import com.android.apksig.apk.ApkUtils;
-import com.android.apksig.internal.asn1.Asn1BerParser;
-import com.android.apksig.internal.asn1.Asn1DecodingException;
-import com.android.apksig.internal.asn1.Asn1DerEncoder;
-import com.android.apksig.internal.asn1.Asn1EncodingException;
import com.android.apksig.internal.util.ByteBufferDataSource;
import com.android.apksig.internal.util.ChainedDataSource;
import com.android.apksig.internal.util.Pair;
import com.android.apksig.internal.util.VerityTreeBuilder;
-import com.android.apksig.internal.x509.RSAPublicKey;
-import com.android.apksig.internal.x509.SubjectPublicKeyInfo;
import com.android.apksig.internal.zip.ZipUtils;
import com.android.apksig.util.DataSink;
import com.android.apksig.util.DataSinks;
@@ -39,7 +33,6 @@
import com.android.apksig.util.RunnablesExecutor;
import java.io.IOException;
-import java.math.BigInteger;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -65,13 +58,17 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class ApkSigningBlockUtils {
- private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
+ private static final char[] HEX_DIGITS = "01234567890abcdef".toCharArray();
private static final long CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES = 1024 * 1024;
public static final int ANDROID_COMMON_PAGE_ALIGNMENT_BYTES = 4096;
public static final byte[] APK_SIGNING_BLOCK_MAGIC =
@@ -778,53 +775,6 @@
byte[] encodedPublicKey = null;
if ("X.509".equals(publicKey.getFormat())) {
encodedPublicKey = publicKey.getEncoded();
- // if the key is an RSA key check for a negative modulus
- if ("RSA".equals(publicKey.getAlgorithm())) {
- try {
- // Parse the encoded public key into the separate elements of the
- // SubjectPublicKeyInfo to obtain the SubjectPublicKey.
- ByteBuffer encodedPublicKeyBuffer = ByteBuffer.wrap(encodedPublicKey);
- SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(
- encodedPublicKeyBuffer, SubjectPublicKeyInfo.class);
- // The SubjectPublicKey is encoded as a bit string within the
- // SubjectPublicKeyInfo. The first byte of the encoding is the number of padding
- // bits; store this and decode the rest of the bit string into the RSA modulus
- // and exponent.
- ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
- byte padding = subjectPublicKeyBuffer.get();
- RSAPublicKey rsaPublicKey = Asn1BerParser.parse(subjectPublicKeyBuffer,
- RSAPublicKey.class);
- // if the modulus is negative then attempt to reencode it with a leading 0 sign
- // byte.
- if (rsaPublicKey.modulus.compareTo(BigInteger.ZERO) < 0) {
- // A negative modulus indicates the leading bit in the integer is 1. Per
- // ASN.1 encoding rules to encode a positive integer with the leading bit
- // set to 1 a byte containing all zeros should precede the integer encoding.
- byte[] encodedModulus = rsaPublicKey.modulus.toByteArray();
- byte[] reencodedModulus = new byte[encodedModulus.length + 1];
- reencodedModulus[0] = 0;
- System.arraycopy(encodedModulus, 0, reencodedModulus, 1,
- encodedModulus.length);
- rsaPublicKey.modulus = new BigInteger(reencodedModulus);
- // Once the modulus has been corrected reencode the RSAPublicKey, then
- // restore the padding value in the bit string and reencode the entire
- // SubjectPublicKeyInfo to be returned to the caller.
- byte[] reencodedRSAPublicKey = Asn1DerEncoder.encode(rsaPublicKey);
- byte[] reencodedSubjectPublicKey =
- new byte[reencodedRSAPublicKey.length + 1];
- reencodedSubjectPublicKey[0] = padding;
- System.arraycopy(reencodedRSAPublicKey, 0, reencodedSubjectPublicKey, 1,
- reencodedRSAPublicKey.length);
- subjectPublicKeyInfo.subjectPublicKey = ByteBuffer.wrap(
- reencodedSubjectPublicKey);
- encodedPublicKey = Asn1DerEncoder.encode(subjectPublicKeyInfo);
- }
- } catch (Asn1DecodingException | Asn1EncodingException e) {
- System.out.println("Caught a exception encoding the public key: " + e);
- e.printStackTrace();
- encodedPublicKey = null;
- }
- }
}
if (encodedPublicKey == null) {
try {
diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java
index f325f8b..d8e4723 100644
--- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java
+++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java
@@ -70,7 +70,7 @@
* protected by signatures inside the block.
*/
- public static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
+ private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
/** Hidden constructor to prevent instantiation. */
private V2SchemeSigner() {}
diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java
index 0ef74a6..51c40bd 100644
--- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java
+++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java
@@ -370,15 +370,7 @@
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();
- }
+ byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
result.addError(
Issue.V2_SIG_PUBLIC_KEY_MISMATCH_BETWEEN_CERTIFICATE_AND_SIGNATURES_RECORD,
diff --git a/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java
index f263323..16a6408 100644
--- a/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java
+++ b/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java
@@ -432,14 +432,7 @@
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();
- }
+ byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
result.addError(
Issue.V3_SIG_PUBLIC_KEY_MISMATCH_BETWEEN_CERTIFICATE_AND_SIGNATURES_RECORD,
diff --git a/src/main/java/com/android/apksig/internal/util/FileChannelDataSource.java b/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
similarity index 88%
rename from src/main/java/com/android/apksig/internal/util/FileChannelDataSource.java
rename to src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
index e4a421a..9c75d26 100644
--- a/src/main/java/com/android/apksig/internal/util/FileChannelDataSource.java
+++ b/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
@@ -27,7 +27,7 @@
/**
* {@link DataSource} backed by a {@link FileChannel} for {@link RandomAccessFile} access.
*/
-public class FileChannelDataSource implements DataSource {
+public class RandomAccessFileDataSource implements DataSource {
private static final int MAX_READ_CHUNK_SIZE = 1024 * 1024;
@@ -36,24 +36,28 @@
private final long mSize;
/**
- * Constructs a new {@code FileChannelDataSource} based on the data contained in the
+ * Constructs a new {@code RandomAccessFileDataSource} based on the data contained in the
* whole file. Changes to the contents of the file, including the size of the file,
* will be visible in this data source.
*/
- public FileChannelDataSource(FileChannel channel) {
- mChannel = channel;
+ public RandomAccessFileDataSource(RandomAccessFile file) {
+ mChannel = file.getChannel();
mOffset = 0;
mSize = -1;
}
/**
- * Constructs a new {@code FileChannelDataSource} based on the data contained in the
+ * Constructs a new {@code RandomAccessFileDataSource} based on the data contained in the
* specified region of the provided file. Changes to the contents of the file will be visible in
* this data source.
*
* @throws IndexOutOfBoundsException if {@code offset} or {@code size} is negative.
*/
- public FileChannelDataSource(FileChannel channel, long offset, long size) {
+ public RandomAccessFileDataSource(RandomAccessFile file, long offset, long size) {
+ this(file.getChannel(), offset, size);
+ }
+
+ private RandomAccessFileDataSource(FileChannel channel, long offset, long size) {
if (offset < 0) {
throw new IndexOutOfBoundsException("offset: " + size);
}
@@ -79,14 +83,14 @@
}
@Override
- public FileChannelDataSource slice(long offset, long size) {
+ public RandomAccessFileDataSource slice(long offset, long size) {
long sourceSize = size();
checkChunkValid(offset, size, sourceSize);
if ((offset == 0) && (size == sourceSize)) {
return this;
}
- return new FileChannelDataSource(mChannel, mOffset + offset, size);
+ return new RandomAccessFileDataSource(mChannel, mOffset + offset, size);
}
@Override
diff --git a/src/main/java/com/android/apksig/internal/x509/RSAPublicKey.java b/src/main/java/com/android/apksig/internal/x509/RSAPublicKey.java
deleted file mode 100644
index 521e067..0000000
--- a/src/main/java/com/android/apksig/internal/x509/RSAPublicKey.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.apksig.internal.x509;
-
-import com.android.apksig.internal.asn1.Asn1Class;
-import com.android.apksig.internal.asn1.Asn1Field;
-import com.android.apksig.internal.asn1.Asn1Type;
-
-import java.math.BigInteger;
-
-/**
- * {@code RSAPublicKey} as specified in RFC 3279.
- */
-@Asn1Class(type = Asn1Type.SEQUENCE)
-public class RSAPublicKey {
- @Asn1Field(index = 0, type = Asn1Type.INTEGER)
- public BigInteger modulus;
-
- @Asn1Field(index = 1, type = Asn1Type.INTEGER)
- public BigInteger publicExponent;
-}
diff --git a/src/main/java/com/android/apksig/util/DataSources.java b/src/main/java/com/android/apksig/util/DataSources.java
index 1f0b40b..00b89d7 100644
--- a/src/main/java/com/android/apksig/util/DataSources.java
+++ b/src/main/java/com/android/apksig/util/DataSources.java
@@ -17,10 +17,9 @@
package com.android.apksig.util;
import com.android.apksig.internal.util.ByteBufferDataSource;
-import com.android.apksig.internal.util.FileChannelDataSource;
+import com.android.apksig.internal.util.RandomAccessFileDataSource;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
/**
* Utility methods for working with {@link DataSource} abstraction.
@@ -45,7 +44,10 @@
* file, including changes to size of file, will be visible in the data source.
*/
public static DataSource asDataSource(RandomAccessFile file) {
- return asDataSource(file.getChannel());
+ if (file == null) {
+ throw new NullPointerException();
+ }
+ return new RandomAccessFileDataSource(file);
}
/**
@@ -53,28 +55,9 @@
* Changes to the file will be visible in the data source.
*/
public static DataSource asDataSource(RandomAccessFile file, long offset, long size) {
- return asDataSource(file.getChannel(), offset, size);
- }
-
- /**
- * Returns a {@link DataSource} backed by the provided {@link FileChannel}. Changes to the
- * file, including changes to size of file, will be visible in the data source.
- */
- public static DataSource asDataSource(FileChannel channel) {
- if (channel == null) {
+ if (file == null) {
throw new NullPointerException();
}
- return new FileChannelDataSource(channel);
- }
-
- /**
- * Returns a {@link DataSource} backed by the provided region of the {@link FileChannel}.
- * Changes to the file will be visible in the data source.
- */
- public static DataSource asDataSource(FileChannel channel, long offset, long size) {
- if (channel == null) {
- throw new NullPointerException();
- }
- return new FileChannelDataSource(channel, offset, size);
+ return new RandomAccessFileDataSource(file, offset, size);
}
}
diff --git a/src/main/java/com/android/apksig/util/RunnablesExecutor.java b/src/main/java/com/android/apksig/util/RunnablesExecutor.java
index 4215810..04ec1d8 100644
--- a/src/main/java/com/android/apksig/util/RunnablesExecutor.java
+++ b/src/main/java/com/android/apksig/util/RunnablesExecutor.java
@@ -17,7 +17,7 @@
package com.android.apksig.util;
public interface RunnablesExecutor {
- RunnablesExecutor SINGLE_THREADED = p -> p.createRunnable().run();
+ RunnablesExecutor SINGLE_THREADED = p -> p.getRunnable().run();
void execute(RunnablesProvider provider);
}
diff --git a/src/main/java/com/android/apksig/util/RunnablesProvider.java b/src/main/java/com/android/apksig/util/RunnablesProvider.java
index f96dcfe..5b7bad2 100644
--- a/src/main/java/com/android/apksig/util/RunnablesProvider.java
+++ b/src/main/java/com/android/apksig/util/RunnablesProvider.java
@@ -17,5 +17,5 @@
package com.android.apksig.util;
public interface RunnablesProvider {
- Runnable createRunnable();
+ Runnable getRunnable();
}
diff --git a/src/test/java/com/android/apksig/ApkSignerTest.java b/src/test/java/com/android/apksig/ApkSignerTest.java
index 65d9149..1434017 100644
--- a/src/test/java/com/android/apksig/ApkSignerTest.java
+++ b/src/test/java/com/android/apksig/ApkSignerTest.java
@@ -21,16 +21,8 @@
import com.android.apksig.ApkVerifier.Issue;
import com.android.apksig.apk.ApkFormatException;
-import com.android.apksig.apk.ApkUtils;
-import com.android.apksig.internal.apk.ApkSigningBlockUtils;
-import com.android.apksig.internal.apk.SignatureInfo;
-import com.android.apksig.internal.apk.v2.V2SchemeSigner;
-import com.android.apksig.internal.apk.v3.V3SchemeSigner;
-import com.android.apksig.internal.asn1.Asn1BerParser;
import com.android.apksig.internal.util.ByteBufferDataSource;
import com.android.apksig.internal.util.Resources;
-import com.android.apksig.internal.x509.RSAPublicKey;
-import com.android.apksig.internal.x509.SubjectPublicKeyInfo;
import com.android.apksig.util.DataSinks;
import com.android.apksig.util.DataSource;
import com.android.apksig.util.DataSources;
@@ -52,8 +44,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.math.BigInteger;
-
@RunWith(JUnit4.class)
public class ApkSignerTest {
@@ -69,10 +59,6 @@
private static final String SECOND_RSA_2048_SIGNER_RESOURCE_NAME = "rsa-2048_2";
private static final String THIRD_RSA_2048_SIGNER_RESOURCE_NAME = "rsa-2048_3";
- // This is the same cert as above with the modulus reencoded to remove the leading 0 sign bit.
- private static final String FIRST_RSA_2048_SIGNER_CERT_WITH_NEGATIVE_MODULUS =
- "rsa-2048_negmod.x509.der";
-
private static final String LINEAGE_RSA_2048_2_SIGNERS_RESOURCE_NAME =
"rsa-2048-lineage-2-signers";
@@ -820,83 +806,6 @@
lineageFromApk.isSignerInLineage((secondSigner)));
}
- @Test
- public void testPublicKeyHasPositiveModulusAfterSigning() throws Exception {
- // The V2 and V3 signature schemes include the public key from the certificate in the
- // signing block. If a certificate with an RSAPublicKey is improperly encoded with a
- // negative modulus this was previously written to the signing block as is and failed on
- // device verification since on device the public key in the certificate was reencoded with
- // the correct encoding for the modulus. This test uses an improperly encoded certificate to
- // sign an APK and verifies that the public key in the signing block is corrected with a
- // positive modulus to allow on device installs / updates.
- List<ApkSigner.SignerConfig> signersList = Collections.singletonList(
- getDefaultSignerConfigFromResources(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
- FIRST_RSA_2048_SIGNER_CERT_WITH_NEGATIVE_MODULUS));
- DataSource signedApk = sign("original.apk", new ApkSigner.Builder(signersList)
- .setV1SigningEnabled(true)
- .setV2SigningEnabled(true)
- .setV3SigningEnabled(true));
- RSAPublicKey v2PublicKey = getRSAPublicKeyFromSigningBlock(signedApk,
- ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
- assertTrue("The modulus in the public key in the V2 signing block must not be negative",
- v2PublicKey.modulus.compareTo(BigInteger.ZERO) > 0);
- RSAPublicKey v3PublicKey = getRSAPublicKeyFromSigningBlock(signedApk,
- ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
- assertTrue("The modulus in the public key in the V3 signing block must not be negative",
- v3PublicKey.modulus.compareTo(BigInteger.ZERO) > 0);
- }
-
- private RSAPublicKey getRSAPublicKeyFromSigningBlock(DataSource apk, int signatureVersionId)
- throws Exception {
- int signatureVersionBlockId;
- switch (signatureVersionId) {
- case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
- signatureVersionBlockId = V2SchemeSigner.APK_SIGNATURE_SCHEME_V2_BLOCK_ID;
- break;
- case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3:
- signatureVersionBlockId = V3SchemeSigner.APK_SIGNATURE_SCHEME_V3_BLOCK_ID;
- break;
- default:
- throw new Exception(
- "Invalid signature version ID specified: " + signatureVersionId);
- }
- ApkUtils.ZipSections zipSections = ApkUtils.findZipSections(apk);
- ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(
- signatureVersionId);
- SignatureInfo signatureInfo = ApkSigningBlockUtils.findSignature(apk, zipSections,
- signatureVersionBlockId, result);
- // FORMAT:
- // * length prefixed sequence of length prefixed signers
- // * length-prefixed signed data
- // * V3+ only - minSDK (uint32)
- // * V3+ only - maxSDK (uint32)
- // * length-prefixed sequence of length-prefixed signatures:
- // * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
- ByteBuffer signers = ApkSigningBlockUtils.getLengthPrefixedSlice(
- signatureInfo.signatureBlock);
- ByteBuffer signer = ApkSigningBlockUtils.getLengthPrefixedSlice(signers);
- // Since all the data is read from the signer block the signedData and signatures are
- // discarded.
- ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
- // For V3+ signature version IDs discard the min / max SDKs as well
- if (signatureVersionId >= ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3) {
- signer.getInt();
- signer.getInt();
- }
- ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
- ByteBuffer publicKey = ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
- SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(publicKey,
- SubjectPublicKeyInfo.class);
- ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
- // The SubjectPublicKey is stored as a bit string in the SubjectPublicKeyInfo with the first
- // byte indicating the number of padding bits in the public key. Read this first byte to
- // allow parsing the rest of the RSAPublicKey as a sequence.
- subjectPublicKeyBuffer.get();
- RSAPublicKey rsaPublicKey = Asn1BerParser.parse(subjectPublicKeyBuffer,
- RSAPublicKey.class);
- return rsaPublicKey;
- }
-
/**
* Asserts that signing the specified golden input file using the provided signing
* configuration produces output identical to the specified golden output file.
@@ -994,13 +903,4 @@
Resources.toCertificateChain(ApkSignerTest.class, keyNameInResources + ".x509.pem");
return new ApkSigner.SignerConfig.Builder(keyNameInResources, privateKey, certs).build();
}
-
- private static ApkSigner.SignerConfig getDefaultSignerConfigFromResources(
- String keyNameInResources, String certNameInResources) throws Exception {
- PrivateKey privateKey = Resources.toPrivateKey(ApkSignerTest.class,
- keyNameInResources + ".pk8");
- List<X509Certificate> certs = Resources.toCertificateChain(ApkSignerTest.class,
- certNameInResources);
- return new ApkSigner.SignerConfig.Builder(keyNameInResources, privateKey, certs).build();
- }
}
diff --git a/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java b/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java
index 1ee3466..7eb7c9b 100644
--- a/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java
+++ b/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java
@@ -101,7 +101,7 @@
List<Future<?>> jobs = new ArrayList<>(jobCount);
for (int i = 0; i < jobCount; i++) {
- jobs.add(forkJoinPool.submit(provider.createRunnable()));
+ jobs.add(forkJoinPool.submit(provider.getRunnable()));
}
try {
diff --git a/src/test/java/com/android/apksig/internal/util/FileChannelDataSourceTest.java b/src/test/java/com/android/apksig/internal/util/RandomAccessFileDataSourceTest.java
similarity index 93%
rename from src/test/java/com/android/apksig/internal/util/FileChannelDataSourceTest.java
rename to src/test/java/com/android/apksig/internal/util/RandomAccessFileDataSourceTest.java
index 9578926..304f1bf 100644
--- a/src/test/java/com/android/apksig/internal/util/FileChannelDataSourceTest.java
+++ b/src/test/java/com/android/apksig/internal/util/RandomAccessFileDataSourceTest.java
@@ -31,14 +31,14 @@
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
-public class FileChannelDataSourceTest {
+public class RandomAccessFileDataSourceTest {
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void testFeedsCorrectData_whenFilePartiallyReadFromBeginning() throws Exception {
byte[] fullFileContent = createFileContent(1024 * 1024 + 987654);
RandomAccessFile raf = createRaf(fullFileContent);
- DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
+ DataSource rafDataSource = new RandomAccessFileDataSource(raf);
ByteArrayDataSink dataSink = new ByteArrayDataSink();
@@ -56,7 +56,7 @@
public void testFeedsCorrectData_whenFilePartiallyReadWithOffset() throws Exception {
byte[] fullFileContent = createFileContent(1024 * 1024 + 987654);
RandomAccessFile raf = createRaf(fullFileContent);
- DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
+ DataSource rafDataSource = new RandomAccessFileDataSource(raf);
ByteArrayDataSink dataSink = new ByteArrayDataSink();
@@ -75,7 +75,7 @@
public void testFeedsCorrectData_whenSeveralMbRead() throws Exception {
byte[] fullFileContent = createFileContent(3 * 1024 * 1024 + 987654);
RandomAccessFile raf = createRaf(fullFileContent);
- DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
+ DataSource rafDataSource = new RandomAccessFileDataSource(raf);
ByteArrayDataSink dataSink = new ByteArrayDataSink();
diff --git a/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java b/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java
index e83c906..8116012 100644
--- a/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java
+++ b/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java
@@ -24,23 +24,15 @@
import java.nio.file.Files;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.runners.JUnit4;
/**
* Tests for the {@link DataSource} returned by
* {@link DataSources#asDataSource(RandomAccessFile, long, long)}.
*/
-@RunWith(Parameterized.class)
+@RunWith(JUnit4.class)
public class DataSourceFromRAFChunkTest extends DataSourceTestBase {
- @Parameterized.Parameters(name = "{0}")
- public static DataSourceFromRAFFactory[] data() {
- return DataSourceFromRAFFactory.values();
- }
-
- @Parameterized.Parameter
- public DataSourceFromRAFFactory factory;
-
@Test
public void testFileSizeChangesNotVisible() throws Exception {
try (CloseableWithDataSource c = createDataSource("abcdefg")) {
@@ -90,7 +82,7 @@
}
return CloseableWithDataSource.of(
- factory.create(f, 2, contents.length),
+ DataSources.asDataSource(f, 2, contents.length),
new DataSourceFromRAFTest.TmpFileCloseable(tmp, f));
}
}
diff --git a/src/test/java/com/android/apksig/util/DataSourceFromRAFFactory.java b/src/test/java/com/android/apksig/util/DataSourceFromRAFFactory.java
deleted file mode 100644
index eec0c11..0000000
--- a/src/test/java/com/android/apksig/util/DataSourceFromRAFFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.apksig.util;
-
-import java.io.RandomAccessFile;
-
-enum DataSourceFromRAFFactory {
- RANDOM_ACCESS_FILE {
- @Override DataSource create(RandomAccessFile file) {
- return DataSources.asDataSource(file);
- }
-
- @Override DataSource create(RandomAccessFile file, long offset, long size) {
- return DataSources.asDataSource(file, offset, size);
- }
- },
- FILE_CHANNEL {
- @Override DataSource create(RandomAccessFile file) {
- return DataSources.asDataSource(file.getChannel());
- }
-
- @Override DataSource create(RandomAccessFile file, long offset, long size) {
- return DataSources.asDataSource(file.getChannel(), offset, size);
- }
- };
-
- abstract DataSource create(RandomAccessFile file);
- abstract DataSource create(RandomAccessFile file, long offset, long size);
-}
diff --git a/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java b/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java
index 50de579..36ef760 100644
--- a/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java
+++ b/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java
@@ -26,23 +26,15 @@
import java.nio.file.Files;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.runners.JUnit4;
/**
* Tests for the {@link DataSource} returned by
* {@link DataSources#asDataSource(java.io.RandomAccessFile)}.
*/
-@RunWith(Parameterized.class)
+@RunWith(JUnit4.class)
public class DataSourceFromRAFTest extends DataSourceTestBase {
- @Parameterized.Parameters(name = "{0}")
- public static DataSourceFromRAFFactory[] data() {
- return DataSourceFromRAFFactory.values();
- }
-
- @Parameterized.Parameter
- public DataSourceFromRAFFactory factory;
-
@Test
public void testFileSizeChangesVisible() throws Exception {
try (CloseableWithDataSource c = createDataSource("abcdefg")) {
@@ -86,7 +78,7 @@
}
return CloseableWithDataSource.of(
- factory.create(f),
+ DataSources.asDataSource(f),
new TmpFileCloseable(tmp, f));
}
diff --git a/src/test/resources/com/android/apksig/rsa-2048_negmod.x509.der b/src/test/resources/com/android/apksig/rsa-2048_negmod.x509.der
deleted file mode 100644
index ba7e78e..0000000
--- a/src/test/resources/com/android/apksig/rsa-2048_negmod.x509.der
+++ /dev/null
Binary files differ