diff options
author | Khaled Abdelmohsen <khelmy@google.com> | 2020-09-25 21:23:33 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-09-25 21:23:33 +0000 |
commit | 8fa509e2a0f4e492b449bad535b439e0df262869 (patch) | |
tree | 53fdb2db70c855d15dc4ada0097494e624c77f4f | |
parent | 70fae881edf1c920f38460cc05eab34e3f6f3238 (diff) | |
parent | 75a024658218358354801ddde2ea754fdda7f8df (diff) | |
download | apksig-8fa509e2a0f4e492b449bad535b439e0df262869.tar.gz |
Add stamp attributes to source stamp signing block am: 75a0246582
Original change: https://googleplex-android-review.googlesource.com/c/platform/tools/apksig/+/12692884
Change-Id: Idf01645c6091f7606b6454ac617a549dcddfa5e2
6 files changed, 88 insertions, 22 deletions
diff --git a/src/main/java/com/android/apksig/DefaultApkSignerEngine.java b/src/main/java/com/android/apksig/DefaultApkSignerEngine.java index 5fb2600..7aa7bf1 100644 --- a/src/main/java/com/android/apksig/DefaultApkSignerEngine.java +++ b/src/main/java/com/android/apksig/DefaultApkSignerEngine.java @@ -381,10 +381,15 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { private ApkSigningBlockUtils.SignerConfig createSourceStampSignerConfig() throws InvalidKeyException { - return createSigningBlockSignerConfig( + ApkSigningBlockUtils.SignerConfig config = createSigningBlockSignerConfig( mSourceStampSignerConfig, /* apkSigningBlockPaddingSupported= */ false, ApkSigningBlockUtils.VERSION_SOURCE_STAMP); + if (mSourceStampSigningCertificateLineage != null) { + config.mSigningCertificateLineage = mSourceStampSigningCertificateLineage.getSubLineage( + config.certificates.get(0)); + } + return config; } private int getMinSdkFromV3SignatureAlgorithms(List<SignatureAlgorithm> algorithms) { diff --git a/src/main/java/com/android/apksig/SigningCertificateLineage.java b/src/main/java/com/android/apksig/SigningCertificateLineage.java index 7645b26..b8f1f8b 100644 --- a/src/main/java/com/android/apksig/SigningCertificateLineage.java +++ b/src/main/java/com/android/apksig/SigningCertificateLineage.java @@ -492,20 +492,8 @@ public class SigningCertificateLineage { return result; } - public byte[] generateV3SignerAttribute() { - // FORMAT (little endian): - // * length-prefixed bytes: attribute pair - // * uint32: ID - // * bytes: value - encoded V3 SigningCertificateLineage - byte[] encodedLineage = - V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage); - int payloadSize = 4 + 4 + encodedLineage.length; - ByteBuffer result = ByteBuffer.allocate(payloadSize); - result.order(ByteOrder.LITTLE_ENDIAN); - result.putInt(4 + encodedLineage.length); - result.putInt(V3SchemeConstants.PROOF_OF_ROTATION_ATTR_ID); - result.put(encodedLineage); - return result.array(); + public byte[] encodeSigningCertificateLineage() { + return V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage); } public List<DefaultApkSignerEngine.SignerConfig> sortSignerConfigs( diff --git a/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java b/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java index afb6bce..465fbb0 100644 --- a/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java +++ b/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java @@ -23,4 +23,5 @@ public class SourceStampConstants { public static final int V1_SOURCE_STAMP_BLOCK_ID = 0x2b09189e; public static final int V2_SOURCE_STAMP_BLOCK_ID = 0x6dff800d; public static final String SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME = "stamp-cert-sha256"; + public static final int PROOF_OF_ROTATION_ATTR_ID = 0x9d6303f7; } diff --git a/src/main/java/com/android/apksig/internal/apk/stamp/V2SourceStampSigner.java b/src/main/java/com/android/apksig/internal/apk/stamp/V2SourceStampSigner.java index 401a43e..46c5b17 100644 --- a/src/main/java/com/android/apksig/internal/apk/stamp/V2SourceStampSigner.java +++ b/src/main/java/com/android/apksig/internal/apk/stamp/V2SourceStampSigner.java @@ -23,11 +23,14 @@ import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsLengt import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedElements; import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes; +import com.android.apksig.SigningCertificateLineage; import com.android.apksig.internal.apk.ApkSigningBlockUtils; import com.android.apksig.internal.apk.ApkSigningBlockUtils.SignerConfig; import com.android.apksig.internal.apk.ContentDigestAlgorithm; import com.android.apksig.internal.util.Pair; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; @@ -35,6 +38,7 @@ import java.security.cert.CertificateEncodingException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -55,7 +59,8 @@ public abstract class V2SourceStampSigner { SourceStampConstants.V2_SOURCE_STAMP_BLOCK_ID; /** Hidden constructor to prevent instantiation. */ - private V2SourceStampSigner() {} + private V2SourceStampSigner() { + } public static Pair<byte[], Integer> generateSourceStampBlock( SignerConfig sourceStampSignerConfig, @@ -96,17 +101,30 @@ public abstract class V2SourceStampSigner { sourceStampBlock.signedDigests = signatureSchemeDigests; + sourceStampBlock.stampAttributes = encodeStampAttributes( + generateStampAttributes(sourceStampSignerConfig.mSigningCertificateLineage)); + sourceStampBlock.signedStampAttributes = + ApkSigningBlockUtils.generateSignaturesOverData(sourceStampSignerConfig, + sourceStampBlock.stampAttributes); + // FORMAT: // * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded) // * length-prefixed sequence of length-prefixed signed signature scheme digests: // * uint32: signature scheme id // * length-prefixed bytes: signed digests for the respective signature scheme + // * length-prefixed bytes: encoded stamp attributes + // * length-prefixed sequence of length-prefixed signed stamp attributes: + // * uint32: signature algorithm id + // * length-prefixed bytes: signed stamp attributes for the respective signature algorithm byte[] sourceStampSignerBlock = encodeAsSequenceOfLengthPrefixedElements( - new byte[][] { - sourceStampBlock.stampCertificate, - encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes( - sourceStampBlock.signedDigests), + new byte[][]{ + sourceStampBlock.stampCertificate, + encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes( + sourceStampBlock.signedDigests), + sourceStampBlock.stampAttributes, + encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes( + sourceStampBlock.signedStampAttributes), }); // FORMAT: @@ -159,8 +177,44 @@ public abstract class V2SourceStampSigner { signedDigest))); } + private static byte[] encodeStampAttributes(Map<Integer, byte[]> stampAttributes) { + if (stampAttributes == null || stampAttributes.isEmpty()) { + return new byte[0]; + } + + int payloadSize = 0; + for (byte[] attributeValue : stampAttributes.values()) { + payloadSize += 4 + attributeValue.length; + } + + // FORMAT (little endian): + // * length-prefixed bytes: pair + // * uint32: ID + // * bytes: value + ByteBuffer result = ByteBuffer.allocate(4 + payloadSize); + result.order(ByteOrder.LITTLE_ENDIAN); + result.putInt(payloadSize); + for (Map.Entry<Integer, byte[]> stampAttribute : stampAttributes.entrySet()) { + result.putInt(stampAttribute.getKey()); + result.put(stampAttribute.getValue()); + } + return result.array(); + } + + private static Map<Integer, byte[]> generateStampAttributes(SigningCertificateLineage lineage) { + HashMap<Integer, byte[]> stampAttributes = new HashMap<>(); + if (lineage != null) { + stampAttributes.put(SourceStampConstants.PROOF_OF_ROTATION_ATTR_ID, + lineage.encodeSigningCertificateLineage()); + } + return stampAttributes; + } + private static final class SourceStampBlock { public byte[] stampCertificate; public List<Pair<Integer, byte[]>> signedDigests; + // Optional stamp attributes that are not required for verification. + public byte[] stampAttributes; + public List<Pair<Integer, byte[]>> signedStampAttributes; } } diff --git a/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeSigner.java index 2c70311..cab2a47 100644 --- a/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeSigner.java +++ b/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeSigner.java @@ -142,6 +142,22 @@ public abstract class V3SchemeSigner { digestInfo.getSecond()); } + public static byte[] generateV3SignerAttribute( + SigningCertificateLineage signingCertificateLineage) { + // FORMAT (little endian): + // * length-prefixed bytes: attribute pair + // * uint32: ID + // * bytes: value - encoded V3 SigningCertificateLineage + byte[] encodedLineage = signingCertificateLineage.encodeSigningCertificateLineage(); + int payloadSize = 4 + 4 + encodedLineage.length; + ByteBuffer result = ByteBuffer.allocate(payloadSize); + result.order(ByteOrder.LITTLE_ENDIAN); + result.putInt(4 + encodedLineage.length); + result.putInt(V3SchemeConstants.PROOF_OF_ROTATION_ATTR_ID); + result.put(encodedLineage); + return result.array(); + } + private static Pair<byte[], Integer> generateApkSignatureSchemeV3Block( List<SignerConfig> signerConfigs, Map<ContentDigestAlgorithm, byte[]> contentDigests) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { @@ -289,7 +305,7 @@ public abstract class V3SchemeSigner { if (signerConfig.mSigningCertificateLineage == null) { return new byte[0]; } - return signerConfig.mSigningCertificateLineage.generateV3SignerAttribute(); + return generateV3SignerAttribute(signerConfig.mSigningCertificateLineage); } private static final class V3SignatureSchemeBlock { diff --git a/src/test/java/com/android/apksig/SigningCertificateLineageTest.java b/src/test/java/com/android/apksig/SigningCertificateLineageTest.java index d1a1568..14cab83 100644 --- a/src/test/java/com/android/apksig/SigningCertificateLineageTest.java +++ b/src/test/java/com/android/apksig/SigningCertificateLineageTest.java @@ -26,6 +26,7 @@ import com.android.apksig.SigningCertificateLineage.SignerConfig; import com.android.apksig.apk.ApkFormatException; import com.android.apksig.internal.apk.ApkSigningBlockUtils; import com.android.apksig.internal.apk.v3.V3SchemeConstants; +import com.android.apksig.internal.apk.v3.V3SchemeSigner; import com.android.apksig.internal.util.ByteBufferUtils; import com.android.apksig.internal.util.Resources; import com.android.apksig.util.DataSource; @@ -244,7 +245,8 @@ public class SigningCertificateLineageTest { // * length-prefixed bytes: attribute pair // * uint32: ID // * bytes: value - encoded V3 SigningCertificateLineage - ByteBuffer v3SignerAttribute = ByteBuffer.wrap(lineage.generateV3SignerAttribute()); + ByteBuffer v3SignerAttribute = ByteBuffer.wrap( + V3SchemeSigner.generateV3SignerAttribute(lineage)); v3SignerAttribute.order(ByteOrder.LITTLE_ENDIAN); ByteBuffer attribute = ApkSigningBlockUtils.getLengthPrefixedSlice(v3SignerAttribute); // The generateV3SignerAttribute method should only use the PROOF_OF_ROTATION_ATTR_ID |