Merge "testVfsCacheConsistency: Error message is startsWith fails"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index d18a9fa..2f7444d 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -376,7 +376,7 @@
private void validateDeviceIdAttestationData(Certificate leaf,
String expectedSerial, String expectedImei, String expectedMeid)
throws CertificateParsingException {
- Attestation attestationRecord = new Attestation((X509Certificate) leaf);
+ Attestation attestationRecord = Attestation.loadFromCertificate((X509Certificate) leaf);
AuthorizationList teeAttestation = attestationRecord.getTeeEnforced();
assertThat(teeAttestation).isNotNull();
validateBrandAttestationRecord(teeAttestation);
@@ -402,7 +402,7 @@
assertThat(attestation).isNotNull();
assertThat(attestation.size()).isGreaterThan(1);
X509Certificate leaf = (X509Certificate) attestation.get(0);
- Attestation attestationRecord = new Attestation(leaf);
+ Attestation attestationRecord = Attestation.loadFromCertificate(leaf);
assertThat(attestationRecord.getAttestationChallenge()).isEqualTo(providedChallenge);
}
diff --git a/tests/security/Android.bp b/tests/security/Android.bp
index d9786a8..12168cc 100644
--- a/tests/security/Android.bp
+++ b/tests/security/Android.bp
@@ -17,6 +17,7 @@
static_libs: [
"bouncycastle-unbundled",
"bouncycastle-bcpkix-unbundled",
+ "cbor-java",
"guava",
"truth-prebuilt",
"testng",
diff --git a/tests/security/src/android/keystore/cts/Asn1Attestation.java b/tests/security/src/android/keystore/cts/Asn1Attestation.java
new file mode 100644
index 0000000..b454130
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/Asn1Attestation.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 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 android.keystore.cts;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+public class Asn1Attestation extends Attestation {
+ static final int ATTESTATION_VERSION_INDEX = 0;
+ static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
+ static final int KEYMASTER_VERSION_INDEX = 2;
+ static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
+ static final int ATTESTATION_CHALLENGE_INDEX = 4;
+ static final int UNIQUE_ID_INDEX = 5;
+ static final int SW_ENFORCED_INDEX = 6;
+ static final int TEE_ENFORCED_INDEX = 7;
+
+ int attestationSecurityLevel;
+
+ /**
+ * Constructs an {@code Asn1Attestation} object from the provided {@link X509Certificate},
+ * extracting the attestation data from the attestation extension.
+ *
+ * @throws CertificateParsingException if the certificate does not contain a properly-formatted
+ * attestation extension.
+ */
+ public Asn1Attestation(X509Certificate x509Cert) throws CertificateParsingException {
+ super(x509Cert);
+ ASN1Sequence seq = getAttestationSequence(x509Cert);
+
+ attestationVersion =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
+ attestationSecurityLevel =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
+ keymasterVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
+ keymasterSecurityLevel =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
+
+ attestationChallenge =
+ Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(ATTESTATION_CHALLENGE_INDEX));
+
+ uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(UNIQUE_ID_INDEX));
+
+ softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
+ teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
+ }
+
+ ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
+ throws CertificateParsingException {
+ byte[] attestationExtensionBytes = x509Cert.getExtensionValue(Attestation.ASN1_OID);
+ if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+ throw new CertificateParsingException("Did not find extension with OID " + ASN1_OID);
+ }
+ return Asn1Utils.getAsn1SequenceFromBytes(attestationExtensionBytes);
+ }
+
+ public int getAttestationSecurityLevel() {
+ return attestationSecurityLevel;
+ }
+
+ public RootOfTrust getRootOfTrust() {
+ return teeEnforced.getRootOfTrust();
+ }
+}
diff --git a/tests/security/src/android/keystore/cts/Attestation.java b/tests/security/src/android/keystore/cts/Attestation.java
index 2285cad..7414908 100644
--- a/tests/security/src/android/keystore/cts/Attestation.java
+++ b/tests/security/src/android/keystore/cts/Attestation.java
@@ -16,71 +16,69 @@
package android.keystore.cts;
+import co.nstant.in.cbor.CborException;
+
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
-import org.bouncycastle.asn1.ASN1Sequence;
-
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* Parses an attestation certificate and provides an easy-to-use interface for examining the
* contents.
*/
-public class Attestation {
- static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
- static final String KEY_USAGE_OID = "2.5.29.15"; // Standard key usage extension.
- static final int ATTESTATION_VERSION_INDEX = 0;
- static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
- static final int KEYMASTER_VERSION_INDEX = 2;
- static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
- static final int ATTESTATION_CHALLENGE_INDEX = 4;
- static final int UNIQUE_ID_INDEX = 5;
- static final int SW_ENFORCED_INDEX = 6;
- static final int TEE_ENFORCED_INDEX = 7;
+public abstract class Attestation {
+ static final String EAT_OID = "1.3.6.1.4.1.11129.2.1.25";
+ static final String ASN1_OID = "1.3.6.1.4.1.11129.2.1.17";
+ static final String KEY_USAGE_OID = "2.5.29.15"; // Standard key usage extension.
public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
public static final int KM_SECURITY_LEVEL_STRONG_BOX = 2;
- private final int attestationVersion;
- private final int attestationSecurityLevel;
- private final int keymasterVersion;
- private final int keymasterSecurityLevel;
- private final byte[] attestationChallenge;
- private final byte[] uniqueId;
- private final AuthorizationList softwareEnforced;
- private final AuthorizationList teeEnforced;
- private final Set<String> unexpectedExtensionOids;
-
+ int attestationVersion;
+ int keymasterVersion;
+ int keymasterSecurityLevel;
+ byte[] attestationChallenge;
+ byte[] uniqueId;
+ AuthorizationList softwareEnforced;
+ AuthorizationList teeEnforced;
+ Set<String> unexpectedExtensionOids;
/**
* Constructs an {@code Attestation} object from the provided {@link X509Certificate},
* extracting the attestation data from the attestation extension.
*
+ * <p>This method ensures that at most one attestation extension is included in the certificate.
+ *
* @throws CertificateParsingException if the certificate does not contain a properly-formatted
- * attestation extension.
+ * attestation extension, if it contains multiple attestation extensions, or if the
+ * attestation extension can not be parsed.
*/
- public Attestation(X509Certificate x509Cert) throws CertificateParsingException {
- ASN1Sequence seq = getAttestationSequence(x509Cert);
+ public static Attestation loadFromCertificate(X509Certificate x509Cert)
+ throws CertificateParsingException {
+ if (x509Cert.getExtensionValue(EAT_OID) == null
+ && x509Cert.getExtensionValue(ASN1_OID) == null) {
+ throw new CertificateParsingException("No attestation extensions found");
+ }
+ if (x509Cert.getExtensionValue(EAT_OID) != null) {
+ if (x509Cert.getExtensionValue(ASN1_OID) != null) {
+ throw new CertificateParsingException("Multiple attestation extensions found");
+ }
+ try {
+ return new EatAttestation(x509Cert);
+ } catch (CborException cbe) {
+ throw new CertificateParsingException("Unable to parse EAT extension", cbe);
+ }
+ }
+ return new Asn1Attestation(x509Cert);
+ }
+
+ Attestation(X509Certificate x509Cert) {
unexpectedExtensionOids = retrieveUnexpectedExtensionOids(x509Cert);
-
- attestationVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
- attestationSecurityLevel = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
- keymasterVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
- keymasterSecurityLevel = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
-
- attestationChallenge =
- Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(Attestation.ATTESTATION_CHALLENGE_INDEX));
-
- uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(Attestation.UNIQUE_ID_INDEX));
-
- softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
- teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
}
public static String securityLevelToString(int attestationSecurityLevel) {
@@ -100,9 +98,9 @@
return attestationVersion;
}
- public int getAttestationSecurityLevel() {
- return attestationSecurityLevel;
- }
+ public abstract int getAttestationSecurityLevel();
+
+ public abstract RootOfTrust getRootOfTrust();
public int getKeymasterVersion() {
return keymasterVersion;
@@ -135,13 +133,15 @@
@Override
public String toString() {
StringBuilder s = new StringBuilder();
- s.append("Attest version: " + attestationVersion);
- s.append("\nAttest security: " + securityLevelToString(attestationSecurityLevel));
+ s.append("Extension type: " + getClass());
+ s.append("\nAttest version: " + attestationVersion);
+ s.append("\nAttest security: " + securityLevelToString(getAttestationSecurityLevel()));
s.append("\nKM version: " + keymasterVersion);
s.append("\nKM security: " + securityLevelToString(keymasterSecurityLevel));
s.append("\nChallenge");
- String stringChallenge = new String(attestationChallenge);
+ String stringChallenge =
+ attestationChallenge != null ? new String(attestationChallenge) : "null";
if (CharMatcher.ascii().matchesAllOf(stringChallenge)) {
s.append(": [" + stringChallenge + "]");
} else {
@@ -159,26 +159,16 @@
return s.toString();
}
- private ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
- throws CertificateParsingException {
- byte[] attestationExtensionBytes = x509Cert.getExtensionValue(KEY_DESCRIPTION_OID);
- if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
- throw new CertificateParsingException(
- "Did not find extension with OID " + KEY_DESCRIPTION_OID);
- }
- return Asn1Utils.getAsn1SequenceFromBytes(attestationExtensionBytes);
- }
-
- private Set<String> retrieveUnexpectedExtensionOids(X509Certificate x509Cert) {
+ Set<String> retrieveUnexpectedExtensionOids(X509Certificate x509Cert) {
return new ImmutableSet.Builder<String>()
- .addAll(x509Cert.getCriticalExtensionOIDs()
- .stream()
- .filter(s -> !KEY_USAGE_OID.equals(s))
- .iterator())
- .addAll(x509Cert.getNonCriticalExtensionOIDs()
- .stream()
- .filter(s -> !KEY_DESCRIPTION_OID.equals(s))
- .iterator())
+ .addAll(
+ x509Cert.getCriticalExtensionOIDs().stream()
+ .filter(s -> !KEY_USAGE_OID.equals(s))
+ .iterator())
+ .addAll(
+ x509Cert.getNonCriticalExtensionOIDs().stream()
+ .filter(s -> !ASN1_OID.equals(s) && !EAT_OID.equals(s))
+ .iterator())
.build();
}
}
diff --git a/tests/security/src/android/keystore/cts/AuthorizationList.java b/tests/security/src/android/keystore/cts/AuthorizationList.java
index 85ac115..dce9b2a 100644
--- a/tests/security/src/android/keystore/cts/AuthorizationList.java
+++ b/tests/security/src/android/keystore/cts/AuthorizationList.java
@@ -19,6 +19,10 @@
import static com.google.common.base.Functions.forMap;
import static com.google.common.collect.Collections2.transform;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -166,6 +170,7 @@
.put(KM_PURPOSE_VERIFY, "VERIFY")
.build();
+ private Integer securityLevel;
private Set<Integer> purposes;
private Integer algorithm;
private Integer keySize;
@@ -331,6 +336,126 @@
}
+ public AuthorizationList(co.nstant.in.cbor.model.Map submodMap)
+ throws CertificateParsingException {
+ for (DataItem key : submodMap.getKeys()) {
+ int keyInt = ((Number) key).getValue().intValue();
+ switch (keyInt) {
+ default:
+ throw new CertificateParsingException("Unknown EAT tag: " + key);
+
+ case EatClaim.SECURITY_LEVEL:
+ securityLevel = eatSecurityLevelToKeymasterSecurityLevel(
+ CborUtils.getInt(submodMap, key));
+ break;
+ case EatClaim.PURPOSE:
+ purposes = CborUtils.getIntSet(submodMap, key);
+ break;
+ case EatClaim.ALGORITHM:
+ algorithm = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.KEY_SIZE:
+ keySize = CborUtils.getInt(submodMap, key);
+ Log.i("Attestation", "Found KEY SIZE, value: " + keySize);
+ break;
+ case EatClaim.DIGEST:
+ digests = CborUtils.getIntSet(submodMap, key);
+ break;
+ case EatClaim.PADDING:
+ paddingModes = CborUtils.getIntSet(submodMap, key);
+ break;
+ case EatClaim.RSA_PUBLIC_EXPONENT:
+ rsaPublicExponent = CborUtils.getLong(submodMap, key);
+ break;
+ case EatClaim.NO_AUTH_REQUIRED:
+ noAuthRequired = true;
+ break;
+ case EatClaim.IAT:
+ creationDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.ORIGIN:
+ origin = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.OS_VERSION:
+ osVersion = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.OS_PATCHLEVEL:
+ osPatchLevel = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.VENDOR_PATCHLEVEL:
+ vendorPatchLevel = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.BOOT_PATCHLEVEL:
+ bootPatchLevel = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.ACTIVE_DATETIME:
+ activeDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.ORIGINATION_EXPIRE_DATETIME:
+ originationExpireDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.USAGE_EXPIRE_DATETIME:
+ usageExpireDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.ROLLBACK_RESISTANT:
+ rollbackResistant = true;
+ break;
+ case EatClaim.ROLLBACK_RESISTANCE:
+ rollbackResistance = true;
+ break;
+ case EatClaim.AUTH_TIMEOUT:
+ authTimeout = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.ALLOW_WHILE_ON_BODY:
+ allowWhileOnBody = true;
+ break;
+ case EatClaim.EC_CURVE:
+ ecCurve = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.USER_AUTH_TYPE:
+ userAuthType = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_APPLICATION_ID:
+ // TODO: The attestation application ID is currently still encoded as an ASN.1
+ // structure. Parse a CBOR structure when it's available instead.
+ attestationApplicationId = new AttestationApplicationId(
+ Asn1Utils.getAsn1EncodableFromBytes(CborUtils.getBytes(submodMap, key)));
+ break;
+ case EatClaim.ATTESTATION_ID_BRAND:
+ brand = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_DEVICE:
+ device = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_PRODUCT:
+ product = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_SERIAL:
+ serialNumber = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.UEID:
+ // TODO: Parse depending on encoding chosen in attestation_record.cpp.
+ imei = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_MEID:
+ meid = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_MANUFACTURER:
+ manufacturer = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_MODEL:
+ model = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.USER_PRESENCE_REQUIRED:
+ userPresenceRequired = CborUtils.getBoolean(submodMap, key);
+ break;
+ case EatClaim.TRUSTED_CONFIRMATION_REQUIRED:
+ confirmationRequired = true;
+ break;
+ }
+ }
+ }
+
public static String algorithmToString(int algorithm) {
switch (algorithm) {
case KM_ALGORITHM_RSA:
@@ -415,6 +540,10 @@
}
}
+ public Integer getSecurityLevel() {
+ return securityLevel;
+ }
+
public Set<Integer> getPurposes() {
return purposes;
}
@@ -607,6 +736,19 @@
return confirmationRequired;
}
+ static int eatSecurityLevelToKeymasterSecurityLevel(int eatSecurityLevel) {
+ switch(eatSecurityLevel) {
+ case EatClaim.SECURITY_LEVEL_UNRESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_SOFTWARE;
+ case EatClaim.SECURITY_LEVEL_SECURE_RESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ case EatClaim.SECURITY_LEVEL_HARDWARE:
+ return Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
+ default:
+ throw new RuntimeException("Invalid EAT security level: " + eatSecurityLevel);
+ }
+ }
+
private String getStringFromAsn1Value(ASN1Primitive value) throws CertificateParsingException {
try {
return Asn1Utils.getStringFromAsn1OctetStreamAssumingUTF8(value);
diff --git a/tests/security/src/android/keystore/cts/CborUtils.java b/tests/security/src/android/keystore/cts/CborUtils.java
new file mode 100644
index 0000000..eeac9b5
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/CborUtils.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 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 android.keystore.cts;
+
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.SimpleValueType;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+import java.nio.charset.StandardCharsets;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+class CborUtils {
+ public static Number toNumber(long l) {
+ return l >= 0 ? new UnsignedInteger(l) : new NegativeInteger(l);
+ }
+
+ public static int getInt(Map map, long index) {
+ DataItem item = map.get(CborUtils.toNumber(index));
+ return ((Number) item).getValue().intValue();
+ }
+
+ public static int getInt(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ return ((Number) item).getValue().intValue();
+ }
+
+ public static long getLong(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ return ((Number) item).getValue().longValue();
+ }
+
+ public static Set<Integer> getIntSet(Map map, DataItem index) {
+ Array array = (Array) map.get(index);
+ Set<Integer> result = new HashSet();
+ for (DataItem item : array.getDataItems()) {
+ result.add(((Number) item).getValue().intValue());
+ }
+ return result;
+ }
+
+ public static Boolean getBoolean(Map map, DataItem index) {
+ SimpleValueType value = ((SimpleValue) map.get(index)).getSimpleValueType();
+ if (value != SimpleValueType.TRUE && value != SimpleValueType.FALSE) {
+ throw new RuntimeException("Only expecting boolean values for " + index);
+ }
+ return (value == SimpleValueType.TRUE);
+ }
+
+ public static List<Boolean> getBooleanList(Map map, DataItem index) {
+ Array array = (Array) map.get(index);
+ List<Boolean> result = new ArrayList();
+ for (DataItem item : array.getDataItems()) {
+ SimpleValueType value = ((SimpleValue) item).getSimpleValueType();
+ if (value == SimpleValueType.FALSE) {
+ result.add(false);
+ } else if (value == SimpleValueType.TRUE) {
+ result.add(true);
+ } else {
+ throw new RuntimeException("Map contains more than booleans: " + map);
+ }
+ }
+ return result;
+ }
+
+ public static Date getDate(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ long epochMillis = ((Number) item).getValue().longValue();
+ return new Date(epochMillis);
+ }
+
+ public static byte[] getBytes(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ return ((ByteString) item).getBytes();
+ }
+
+ public static String getString(Map map, DataItem index) {
+ byte[] bytes = getBytes(map, index);
+ return new String(bytes, StandardCharsets.UTF_8);
+ }
+}
diff --git a/tests/security/src/android/keystore/cts/EatAttestation.java b/tests/security/src/android/keystore/cts/EatAttestation.java
new file mode 100644
index 0000000..21ef0db
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/EatAttestation.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2020 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 android.keystore.cts;
+
+import android.util.Log;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.UnicodeString;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+public class EatAttestation extends Attestation {
+ static final String TAG = "EatAttestation";
+ final Map extension;
+ final RootOfTrust rootOfTrust;
+
+ /**
+ * Constructs an {@code EatAttestation} object from the provided {@link X509Certificate},
+ * extracting the attestation data from the attestation extension.
+ *
+ * @throws CertificateParsingException if the certificate does not contain a properly-formatted
+ * attestation extension.
+ */
+ public EatAttestation(X509Certificate x509Cert)
+ throws CertificateParsingException, CborException {
+ super(x509Cert);
+ extension = getEatExtension(x509Cert);
+
+ RootOfTrust.Builder rootOfTrustBuilder = new RootOfTrust.Builder();
+ List<Boolean> bootState = null;
+ boolean officialBuild = false;
+
+ for (DataItem key : extension.getKeys()) {
+ int keyInt = ((Number) key).getValue().intValue();
+ switch (keyInt) {
+ default:
+ throw new CertificateParsingException(
+ "Unknown EAT tag: " + key + "\n in EAT extension:\n" + toString());
+
+ case EatClaim.ATTESTATION_VERSION:
+ attestationVersion = CborUtils.getInt(extension, key);
+ break;
+ case EatClaim.KEYMASTER_VERSION:
+ keymasterVersion = CborUtils.getInt(extension, key);
+ break;
+ case EatClaim.SECURITY_LEVEL:
+ keymasterSecurityLevel =
+ eatSecurityLevelToKeymintSecurityLevel(
+ CborUtils.getInt(extension, key));
+ break;
+ case EatClaim.SUBMODS:
+ Map submods = (Map) extension.get(key);
+ softwareEnforced =
+ new AuthorizationList(
+ (Map) submods.get(new UnicodeString(EatClaim.SUBMOD_SOFTWARE)));
+ teeEnforced =
+ new AuthorizationList(
+ (Map) submods.get(new UnicodeString(EatClaim.SUBMOD_TEE)));
+ break;
+ case EatClaim.VERIFIED_BOOT_KEY:
+ rootOfTrustBuilder.setVerifiedBootKey(CborUtils.getBytes(extension, key));
+ break;
+ case EatClaim.DEVICE_LOCKED:
+ rootOfTrustBuilder.setDeviceLocked(CborUtils.getBoolean(extension, key));
+ break;
+ case EatClaim.BOOT_STATE:
+ bootState = CborUtils.getBooleanList(extension, key);
+ break;
+ case EatClaim.OFFICIAL_BUILD:
+ officialBuild = CborUtils.getBoolean(extension, key);
+ break;
+ case EatClaim.NONCE:
+ attestationChallenge = CborUtils.getBytes(extension, key);
+ break;
+ case EatClaim.CTI:
+ Log.i(TAG, "Got CTI claim: " + CborUtils.getBytes(extension, key));
+ uniqueId = CborUtils.getBytes(extension, key);
+ break;
+ case EatClaim.VERIFIED_BOOT_HASH:
+ // TODO: ignored for now, as this is not checked in original ASN.1 tests
+ break;
+ }
+ }
+
+ if (bootState != null) {
+ rootOfTrustBuilder.setVerifiedBootState(
+ eatBootStateTypeToVerifiedBootState(bootState, officialBuild));
+ }
+ rootOfTrust = rootOfTrustBuilder.build();
+ }
+
+ /** Find the submod containing the key information, and return its security level. */
+ public int getAttestationSecurityLevel() {
+ if (teeEnforced != null && teeEnforced.getAlgorithm() != null) {
+ return teeEnforced.getSecurityLevel();
+ } else if (softwareEnforced != null && softwareEnforced.getAlgorithm() != null) {
+ return softwareEnforced.getSecurityLevel();
+ } else {
+ return -1;
+ }
+ }
+
+ public RootOfTrust getRootOfTrust() {
+ return rootOfTrust;
+ }
+
+ public String toString() {
+ return super.toString() + "\nEncoded CBOR: " + extension;
+ }
+
+ Map getEatExtension(X509Certificate x509Cert)
+ throws CertificateParsingException, CborException {
+ byte[] attestationExtensionBytes = x509Cert.getExtensionValue(Attestation.EAT_OID);
+ if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+ throw new CertificateParsingException("Did not find extension with OID " + EAT_OID);
+ }
+ ASN1Encodable asn1 = Asn1Utils.getAsn1EncodableFromBytes(attestationExtensionBytes);
+ byte[] cborBytes = Asn1Utils.getByteArrayFromAsn1(asn1);
+ List<DataItem> cbor = CborDecoder.decode(cborBytes);
+ return (Map) cbor.get(0);
+ }
+
+ static int eatSecurityLevelToKeymintSecurityLevel(int eatSecurityLevel) {
+ switch (eatSecurityLevel) {
+ case EatClaim.SECURITY_LEVEL_UNRESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_SOFTWARE;
+ case EatClaim.SECURITY_LEVEL_SECURE_RESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ case EatClaim.SECURITY_LEVEL_HARDWARE:
+ return Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
+ default:
+ throw new RuntimeException("Invalid EAT security level: " + eatSecurityLevel);
+ }
+ }
+
+ static int eatBootStateTypeToVerifiedBootState(List<Boolean> bootState, Boolean officialBuild) {
+ if (bootState.size() != 5) {
+ throw new RuntimeException("Boot state map has unexpected size: " + bootState.size());
+ }
+ if (bootState.get(4)) {
+ throw new RuntimeException("debug-permanent-disable must never be true: " + bootState);
+ }
+ boolean verifiedOrSelfSigned = bootState.get(0);
+ if (verifiedOrSelfSigned != bootState.get(1)
+ && verifiedOrSelfSigned != bootState.get(2)
+ && verifiedOrSelfSigned != bootState.get(3)) {
+ throw new RuntimeException("Unexpected boot state: " + bootState);
+ }
+
+ if (officialBuild) {
+ if (!verifiedOrSelfSigned) {
+ throw new AssertionError("Non-verified official build");
+ }
+ return RootOfTrust.KM_VERIFIED_BOOT_VERIFIED;
+ } else {
+ return verifiedOrSelfSigned
+ ? RootOfTrust.KM_VERIFIED_BOOT_SELF_SIGNED
+ : RootOfTrust.KM_VERIFIED_BOOT_UNVERIFIED;
+ }
+ }
+}
diff --git a/tests/security/src/android/keystore/cts/EatClaim.java b/tests/security/src/android/keystore/cts/EatClaim.java
new file mode 100644
index 0000000..1130037
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/EatClaim.java
@@ -0,0 +1,112 @@
+package android.keystore.cts;
+
+import android.security.keymaster.KeymasterDefs;
+
+class EatClaim {
+ public static final int IAT = 6;
+ public static final int CTI = 7;
+
+ public static final int NONCE = -75008;
+ public static final int UEID = -75009;
+
+ public static final int SECURITY_LEVEL = -76002;
+ public static final int SECURITY_LEVEL_UNRESTRICTED = 1;
+ public static final int SECURITY_LEVEL_SECURE_RESTRICTED = 3;
+ public static final int SECURITY_LEVEL_HARDWARE = 4;
+
+ public static final int BOOT_STATE = -76003;
+ public static final int SUBMODS = -76000;
+
+ private static final int PRIVATE_BASE = -80000;
+
+ public static final int PURPOSE = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_PURPOSE);
+ public static final int ALGORITHM =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ALGORITHM);
+ public static final int KEY_SIZE = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_KEY_SIZE);
+ public static final int BLOCK_MODE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_BLOCK_MODE);
+ public static final int DIGEST = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_DIGEST);
+ public static final int PADDING = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_PADDING);
+ public static final int CALLER_NONCE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_CALLER_NONCE);
+ public static final int MIN_MAC_LENGTH =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_MIN_MAC_LENGTH);
+ public static final int KDF = PRIVATE_BASE - 9;
+
+ public static final int EC_CURVE = PRIVATE_BASE - 10;
+ public static final int EAT_EC_CURVE_P_224 = 0;
+ public static final int EAT_EC_CURVE_P_256 = 1;
+ public static final int EAT_EC_CURVE_P_384 = 2;
+ public static final int EAT_EC_CURVE_P_521 = 3;
+
+ public static final int RSA_PUBLIC_EXPONENT =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT);
+
+ public static final int ROLLBACK_RESISTANCE = PRIVATE_BASE - 303;
+ public static final int EARLY_BOOT_ONLY = PRIVATE_BASE - 305;
+
+ public static final int ACTIVE_DATETIME =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+ public static final int ORIGINATION_EXPIRE_DATETIME =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+ public static final int USAGE_EXPIRE_DATETIME =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+
+ public static final int NO_AUTH_REQUIRED =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+ public static final int USER_AUTH_TYPE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_USER_AUTH_TYPE);
+ public static final int AUTH_TIMEOUT =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_AUTH_TIMEOUT);
+ public static final int ALLOW_WHILE_ON_BODY =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+ public static final int USER_PRESENCE_REQUIRED = PRIVATE_BASE - 507;
+ public static final int TRUSTED_CONFIRMATION_REQUIRED =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
+ public static final int UNLOCKED_DEVICE_REQUIRED =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+
+ public static final int APPLICATION_ID =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_APPLICATION_ID);
+
+ public static final int ORIGIN = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ORIGIN);
+ // TODO: hardcoded while KeymasterDefs uses the same value for
+ // ROLLBACK_RESISTANCE and ROLLBACK_RESISTANT
+ public static final int ROLLBACK_RESISTANT = PRIVATE_BASE - 703;
+ public static final int OS_VERSION = PRIVATE_BASE - 705;
+ public static final int OS_PATCHLEVEL = PRIVATE_BASE - 706;
+ public static final int ATTESTATION_APPLICATION_ID = PRIVATE_BASE - 709;
+ public static final int ATTESTATION_ID_BRAND =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND);
+ public static final int ATTESTATION_ID_DEVICE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE);
+ public static final int ATTESTATION_ID_PRODUCT =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT);
+ public static final int ATTESTATION_ID_SERIAL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL);
+ public static final int ATTESTATION_ID_MEID =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID);
+ public static final int ATTESTATION_ID_MANUFACTURER =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER);
+ public static final int ATTESTATION_ID_MODEL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL);
+ public static final int VENDOR_PATCHLEVEL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_VENDOR_PATCHLEVEL);
+ public static final int BOOT_PATCHLEVEL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_BOOT_PATCHLEVEL);
+ public static final int DEVICE_UNIQUE_ATTESTATION =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
+ public static final int IDENTITY_CREDENTIAL_KEY = PRIVATE_BASE - 721;
+
+ private static final int NON_KM_BASE = PRIVATE_BASE - 2000;
+
+ public static final int VERIFIED_BOOT_KEY = NON_KM_BASE - 1;
+ public static final int DEVICE_LOCKED = NON_KM_BASE - 2;
+ public static final int VERIFIED_BOOT_HASH = NON_KM_BASE - 3;
+ public static final int ATTESTATION_VERSION = NON_KM_BASE - 4;
+ public static final int KEYMASTER_VERSION = NON_KM_BASE - 5;
+ public static final int OFFICIAL_BUILD = NON_KM_BASE - 6;
+
+ public static final String SUBMOD_SOFTWARE = "software";
+ public static final String SUBMOD_TEE = "tee";
+}
diff --git a/tests/security/src/android/keystore/cts/RootOfTrust.java b/tests/security/src/android/keystore/cts/RootOfTrust.java
index 9957702..a115874 100644
--- a/tests/security/src/android/keystore/cts/RootOfTrust.java
+++ b/tests/security/src/android/keystore/cts/RootOfTrust.java
@@ -51,6 +51,13 @@
Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_STATE_INDEX));
}
+
+ RootOfTrust(byte[] verifiedBootKey, boolean deviceLocked, int verifiedBootState) {
+ this.verifiedBootKey = verifiedBootKey;
+ this.deviceLocked = deviceLocked;
+ this.verifiedBootState = verifiedBootState;
+ }
+
public static String verifiedBootStateToString(int verifiedBootState) {
switch (verifiedBootState) {
case KM_VERIFIED_BOOT_VERIFIED:
@@ -82,11 +89,35 @@
public String toString() {
return new StringBuilder()
.append("\nVerified boot Key: ")
- .append(BaseEncoding.base64().encode(verifiedBootKey))
+ .append(verifiedBootKey != null ?
+ BaseEncoding.base64().encode(verifiedBootKey) :
+ "null")
.append("\nDevice locked: ")
.append(deviceLocked)
.append("\nVerified boot state: ")
.append(verifiedBootStateToString(verifiedBootState))
.toString();
}
+
+ public static class Builder {
+ private byte[] verifiedBootKey;
+ private boolean deviceLocked = false;
+ private int verifiedBootState = -1;
+
+ public Builder setVerifiedBootKey(byte[] verifiedBootKey) {
+ this.verifiedBootKey = verifiedBootKey;
+ return this;
+ }
+ public Builder setDeviceLocked(boolean deviceLocked) {
+ this.deviceLocked = deviceLocked;
+ return this;
+ }
+ public Builder setVerifiedBootState(int verifiedBootState) {
+ this.verifiedBootState = verifiedBootState;
+ return this;
+ }
+ public RootOfTrust build() {
+ return new RootOfTrust(verifiedBootKey, deviceLocked, verifiedBootState);
+ }
+ }
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index d457995..1af904f 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -234,7 +234,8 @@
assertEquals(1, certificates.length);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID));
+ assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID));
+ assertNull(attestationCert.getExtensionValue(Attestation.EAT_OID));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -272,7 +273,7 @@
verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext()));
X509Certificate attestationCert = (X509Certificate) certificates[0];
- checkDeviceLocked(new Attestation(attestationCert));
+ checkDeviceLocked(Attestation.loadFromCertificate(attestationCert));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -402,7 +403,7 @@
assertEquals(1, certificates.length);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID));
+ assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -441,7 +442,7 @@
verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext()));
X509Certificate attestationCert = (X509Certificate) certificates[0];
- checkDeviceLocked(new Attestation(attestationCert));
+ checkDeviceLocked(Attestation.loadFromCertificate(attestationCert));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -559,12 +560,13 @@
verifyCertificateChain(certificates, false /* expectStrongBox */);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- Attestation attestation = new Attestation(attestationCert);
+ Attestation attestation = Attestation.loadFromCertificate(attestationCert);
- checkRsaKeyDetails(attestation, keySize, purposes, ImmutableSet.copyOf(paddingModes));
+ checkRsaKeyDetails(attestation, keySize, purposes,
+ ImmutableSet.copyOf(paddingModes));
checkKeyUsage(attestationCert, purposes);
- checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates,
- devicePropertiesAttestation, attestation);
+ checkKeyIndependentAttestationInfo(challenge, purposes, startTime,
+ includeValidityDates, devicePropertiesAttestation, attestation);
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -618,12 +620,12 @@
verifyCertificateChain(certificates, false /* expectStrongBox */);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- Attestation attestation = new Attestation(attestationCert);
+ Attestation attestation = Attestation.loadFromCertificate(attestationCert);
checkEcKeyDetails(attestation, ecCurve, keySize);
checkKeyUsage(attestationCert, purposes);
- checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates,
- devicePropertiesAttestation, attestation);
+ checkKeyIndependentAttestationInfo(challenge, purposes, startTime,
+ includeValidityDates, devicePropertiesAttestation, attestation);
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -635,6 +637,7 @@
int kmVersion = attestation.getKeymasterVersion();
assertNull(attestation.getTeeEnforced().getAttestationApplicationId());
aaid = attestation.getSoftwareEnforced().getAttestationApplicationId();
+
if (kmVersion >= 3) {
// must be present and correct
assertNotNull(aaid);
@@ -695,9 +698,11 @@
checkUnexpectedOids(attestation);
checkAttestationSecurityLevelDependentParams(attestation);
assertNotNull(attestation.getAttestationChallenge());
- assertTrue(Arrays.equals(challenge, attestation.getAttestationChallenge()));
- assertNotNull(attestation.getUniqueId());
- assertEquals(0, attestation.getUniqueId().length);
+ assertThat(attestation.getAttestationChallenge(), is(challenge));
+ // In EAT, this is null if not filled in. In ASN.1, this is an array with length 0.
+ if (attestation.getUniqueId() != null) {
+ assertEquals(0, attestation.getUniqueId().length);
+ }
checkPurposes(attestation, purposes);
checkDigests(attestation,
ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512));
@@ -919,8 +924,8 @@
@SuppressWarnings("unchecked")
private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
- assertThat("Attestation version must be 1, 2, 3, or 4", attestation.getAttestationVersion(),
- either(is(1)).or(is(2)).or(is(3)).or(is(4)));
+ assertThat("Attestation version must be 1, 2, 3, 4 or 5", attestation.getAttestationVersion(),
+ either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(5)));
AuthorizationList teeEnforced = attestation.getTeeEnforced();
AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
@@ -997,7 +1002,7 @@
}
private void checkRootOfTrust(Attestation attestation, boolean requireLocked) {
- RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
+ RootOfTrust rootOfTrust = attestation.getRootOfTrust();
assertNotNull(rootOfTrust);
assertNotNull(rootOfTrust.getVerifiedBootKey());
assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index a89ba85..cbcaf24 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -3011,6 +3011,12 @@
<permission android:name="android.permission.DUMP"
android:protectionLevel="signature|privileged|development" />
+ <!-- Allows an application to start tracing for InputMethod and WindowManager.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_UI_TRACING"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- Allows an application to read the low-level system log files.
<p>Not for use by third-party applications, because
Log entries can contain the user's private information. -->