From 10d19e98081bec0e2ee5274f2c46d02d036ce89f Mon Sep 17 00:00:00 2001 From: Daniel Cashman Date: Wed, 28 Mar 2018 15:58:14 -0700 Subject: [PATCH] Require signing cert history certs to be unique. Bug: 73943012 Test: android.appsecurity.cts.PkgInstallSignatureVerificationTest Change-Id: Id7e91c60f1619ef793d73a9dd736debf7ad2ae0c (cherry picked from commit ef05408bcdcb32d005f91ca295a1e514845a58f4) --- .../util/apk/ApkSignatureSchemeV3Verifier.java | 8 +++++++ .../android/util/apk/VerbatimX509Certificate.java | 28 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index 4431bcef1ff4..758cd2b877f2 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -62,6 +62,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -457,6 +458,7 @@ public class ApkSignatureSchemeV3Verifier { // get the version code, but don't do anything with it: creator knew about all our flags porBuf.getInt(); + HashSet certHistorySet = new HashSet<>(); while (porBuf.hasRemaining()) { levelCount++; ByteBuffer level = getLengthPrefixedSlice(porBuf); @@ -495,6 +497,12 @@ public class ApkSignatureSchemeV3Verifier { lastCert = new VerbatimX509Certificate(lastCert, encodedCert); lastSigAlgorithm = sigAlgorithm; + if (certHistorySet.contains(lastCert)) { + throw new SecurityException("Encountered duplicate entries in " + + "Proof-of-rotation record at certificate #" + levelCount + ". All " + + "signing certificates should be unique"); + } + certHistorySet.add(lastCert); certs.add(lastCert); flagsList.add(flags); } diff --git a/core/java/android/util/apk/VerbatimX509Certificate.java b/core/java/android/util/apk/VerbatimX509Certificate.java index 9984c6d26c64..391c5fc39416 100644 --- a/core/java/android/util/apk/VerbatimX509Certificate.java +++ b/core/java/android/util/apk/VerbatimX509Certificate.java @@ -18,6 +18,7 @@ package android.util.apk; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; +import java.util.Arrays; /** * For legacy reasons we need to return exactly the original encoded certificate bytes, instead @@ -25,6 +26,7 @@ import java.security.cert.X509Certificate; */ class VerbatimX509Certificate extends WrappedX509Certificate { private final byte[] mEncodedVerbatim; + private int mHash = -1; VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) { super(wrapped); @@ -35,4 +37,30 @@ class VerbatimX509Certificate extends WrappedX509Certificate { public byte[] getEncoded() throws CertificateEncodingException { return mEncodedVerbatim; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VerbatimX509Certificate)) return false; + + try { + byte[] a = this.getEncoded(); + byte[] b = ((VerbatimX509Certificate) o).getEncoded(); + return Arrays.equals(a, b); + } catch (CertificateEncodingException e) { + return false; + } + } + + @Override + public int hashCode() { + if (mHash == -1) { + try { + mHash = Arrays.hashCode(this.getEncoded()); + } catch (CertificateEncodingException e) { + mHash = 0; + } + } + return mHash; + } } -- 2.11.0