blob: 1265c46ef765a9f112c293e0733501cf43d6d314 [file] [log] [blame]
/* Copyright 2019, The Android Open Source Project, Inc.
*
* 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.google.android.attestation;
import static com.google.android.attestation.AuthorizationList.UserAuthType.FINGERPRINT;
import static com.google.android.attestation.AuthorizationList.UserAuthType.PASSWORD;
import static com.google.android.attestation.AuthorizationList.UserAuthType.USER_AUTH_TYPE_ANY;
import static com.google.android.attestation.AuthorizationList.UserAuthType.USER_AUTH_TYPE_NONE;
import static com.google.android.attestation.AuthorizationList.userAuthTypeToEnum;
import static com.google.android.attestation.Constants.UINT32_MAX;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.time.Instant;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.util.encoders.Base64;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test for {@link AuthorizationList}. */
@RunWith(JUnit4.class)
public class AuthorizationListTest {
// Generated from certificate with RSA Algorithm and StrongBox Security Level
private static final String SW_ENFORCED_EXTENSION_DATA =
"MIIBzb+FPQgCBgFr9iKgzL+FRYIBuwSCAbcwggGzMYIBizAMBAdhbmRyb2lkAgEdMBkEFGNvbS5hbmRyb2lkLmtleWNo"
+ "YWluAgEdMBkEFGNvbS5hbmRyb2lkLnNldHRpbmdzAgEdMBkEFGNvbS5xdGkuZGlhZ3NlcnZpY2VzAgEdMBoEFW"
+ "NvbS5hbmRyb2lkLmR5bnN5c3RlbQIBHTAdBBhjb20uYW5kcm9pZC5pbnB1dGRldmljZXMCAR0wHwQaY29tLmFu"
+ "ZHJvaWQubG9jYWx0cmFuc3BvcnQCAR0wHwQaY29tLmFuZHJvaWQubG9jYXRpb24uZnVzZWQCAR0wHwQaY29tLm"
+ "FuZHJvaWQuc2VydmVyLnRlbGVjb20CAR0wIAQbY29tLmFuZHJvaWQud2FsbHBhcGVyYmFja3VwAgEdMCEEHGNv"
+ "bS5nb29nbGUuU1NSZXN0YXJ0RGV0ZWN0b3ICAR0wIgQdY29tLmdvb2dsZS5hbmRyb2lkLmhpZGRlbm1lbnUCAQ"
+ "EwIwQeY29tLmFuZHJvaWQucHJvdmlkZXJzLnNldHRpbmdzAgEdMSIEIDAao8sIETRQHEXxQiq8ZsJCJP1d7V/c"
+ "jxfmlxdv2Gaq";
private static final String TEE_ENFORCED_EXTENSION_DATA =
"MIGwoQgxBgIBAgIBA6IDAgEBowQCAggApQUxAwIBBKYIMQYCAQMCAQW/gUgFAgMBAAG/g3cCBQC/hT4DAgEAv4VATDBK"
+ "BCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAoBAgQgco2xJ08fHPFXHeQ4CwSKVUrEo4Dnb1"
+ "NVCDUpCEqTeAG/hUEDAgEAv4VCBQIDAxSzv4VOBgIEATQV8b+FTwYCBAE0Few=";
private static final int ATTESTATION_VERSION = 3;
// Some enum values, complete list can be found at:
// https://source.android.com/security/keystore/tags
private static final int PURPOSE_SIGN = 2;
private static final int PURPOSE_VERIFY = 3;
private static final int ALGORITHM_RSA = 1;
private static final int DIGEST_SHA_2_256 = 4;
private static final int PADDING_RSA_PSS = 3;
private static final int PADDING_RSA_1_5_SIGN = 5;
private static final int ORIGIN_GENERATED = 0;
// 2019-07-15T14:56:32.972Z
private static final Instant EXPECTED_SW_CREATION_DATETIME = Instant.ofEpochMilli(1563202592972L);
private static final byte[] EXPECTED_SW_ATTESTATION_APPLICATION_ID_BYTES =
Base64.decode(
"MIIBszGCAYswDAQHYW5kcm9pZAIBHTAZBBRjb20uYW5kcm9pZC5rZXljaGFpbgIBHTAZBBRjb20uYW5kcm9pZC5z"
+ "ZXR0aW5ncwIBHTAZBBRjb20ucXRpLmRpYWdzZXJ2aWNlcwIBHTAaBBVjb20uYW5kcm9pZC5keW5zeXN0ZW"
+ "0CAR0wHQQYY29tLmFuZHJvaWQuaW5wdXRkZXZpY2VzAgEdMB8EGmNvbS5hbmRyb2lkLmxvY2FsdHJhbnNw"
+ "b3J0AgEdMB8EGmNvbS5hbmRyb2lkLmxvY2F0aW9uLmZ1c2VkAgEdMB8EGmNvbS5hbmRyb2lkLnNlcnZlci"
+ "50ZWxlY29tAgEdMCAEG2NvbS5hbmRyb2lkLndhbGxwYXBlcmJhY2t1cAIBHTAhBBxjb20uZ29vZ2xlLlNT"
+ "UmVzdGFydERldGVjdG9yAgEdMCIEHWNvbS5nb29nbGUuYW5kcm9pZC5oaWRkZW5tZW51AgEBMCMEHmNvbS"
+ "5hbmRyb2lkLnByb3ZpZGVycy5zZXR0aW5ncwIBHTEiBCAwGqPLCBE0UBxF8UIqvGbCQiT9Xe1f3I8X5pcX"
+ "b9hmqg==");
private static final ImmutableSet<Integer> EXPECTED_TEE_PURPOSE =
ImmutableSet.of(PURPOSE_SIGN, PURPOSE_VERIFY);
private static final Integer EXPECTED_TEE_ALGORITHM = ALGORITHM_RSA;
private static final Integer EXPECTED_TEE_KEY_SIZE = 2048;
private static final ImmutableSet<Integer> EXPECTED_TEE_DIGEST =
ImmutableSet.of(DIGEST_SHA_2_256);
private static final ImmutableSet<Integer> EXPECTED_TEE_PADDING =
ImmutableSet.of(PADDING_RSA_PSS, PADDING_RSA_1_5_SIGN);
private static final Long EXPECTED_TEE_RSA_PUBLIC_COMPONENT = 65537L;
private static final Integer EXPECTED_TEE_ORIGIN = ORIGIN_GENERATED;
private static final Integer EXPECTED_TEE_OS_VERSION = 0;
private static final Integer EXPECTED_TEE_OS_PATCH_LEVEL = 201907;
private static final Integer EXPECTED_TEE_VENDOR_PATCH_LEVEL = 20190705;
private static final Integer EXPECTED_TEE_BOOT_PATCH_LEVEL = 20190700;
private static ASN1Encodable[] getEncodableAuthorizationList(String extensionData)
throws IOException {
byte[] extensionDataBytes = Base64.decode(extensionData);
return ((ASN1Sequence) ASN1Sequence.fromByteArray(extensionDataBytes)).toArray();
}
@Test
public void testCanParseAuthorizationListFromSwEnforced() throws IOException {
AuthorizationList authorizationList =
AuthorizationList.createAuthorizationList(
getEncodableAuthorizationList(SW_ENFORCED_EXTENSION_DATA), ATTESTATION_VERSION);
assertThat(authorizationList.creationDateTime).hasValue(EXPECTED_SW_CREATION_DATETIME);
assertThat(authorizationList.rootOfTrust).isEmpty();
assertThat(authorizationList.attestationApplicationId).isPresent();
assertThat(authorizationList.attestationApplicationIdBytes)
.hasValue(EXPECTED_SW_ATTESTATION_APPLICATION_ID_BYTES);
}
@Test
public void testCanParseAuthorizationListFromTeeEnforced() throws IOException {
AuthorizationList authorizationList =
AuthorizationList.createAuthorizationList(
getEncodableAuthorizationList(TEE_ENFORCED_EXTENSION_DATA), ATTESTATION_VERSION);
assertThat(authorizationList.purpose).hasValue(EXPECTED_TEE_PURPOSE);
assertThat(authorizationList.algorithm).hasValue(EXPECTED_TEE_ALGORITHM);
assertThat(authorizationList.keySize).hasValue(EXPECTED_TEE_KEY_SIZE);
assertThat(authorizationList.digest).hasValue(EXPECTED_TEE_DIGEST);
assertThat(authorizationList.padding).hasValue(EXPECTED_TEE_PADDING);
assertThat(authorizationList.rsaPublicExponent).hasValue(EXPECTED_TEE_RSA_PUBLIC_COMPONENT);
assertThat(authorizationList.noAuthRequired).isTrue();
assertThat(authorizationList.origin).hasValue(EXPECTED_TEE_ORIGIN);
assertThat(authorizationList.rootOfTrust).isPresent();
assertThat(authorizationList.osVersion).hasValue(EXPECTED_TEE_OS_VERSION);
assertThat(authorizationList.osPatchLevel).hasValue(EXPECTED_TEE_OS_PATCH_LEVEL);
assertThat(authorizationList.vendorPatchLevel).hasValue(EXPECTED_TEE_VENDOR_PATCH_LEVEL);
assertThat(authorizationList.bootPatchLevel).hasValue(EXPECTED_TEE_BOOT_PATCH_LEVEL);
}
@Test
public void testUserAuthTypeToEnum() {
assertThat(userAuthTypeToEnum(0L)).isEqualTo(USER_AUTH_TYPE_NONE);
assertThat(userAuthTypeToEnum(1L)).isEqualTo(PASSWORD);
assertThat(userAuthTypeToEnum(2L)).isEqualTo(FINGERPRINT);
assertThat(userAuthTypeToEnum(UINT32_MAX)).isEqualTo(USER_AUTH_TYPE_ANY);
try {
userAuthTypeToEnum(3L);
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().contains("Invalid User Auth Type.");
}
}
}