Adds the basic API of the attestation verification framework.
Bug: 201696614 Change-Id: I59d90091106db6e6343f3a6fb698f01559841137 Test: N/A (non-functional API definition) CTS-Coverage-Bug: 201337503
This commit is contained in:
@@ -3842,6 +3842,7 @@ public abstract class Context {
|
||||
UWB_SERVICE,
|
||||
MEDIA_METRICS_SERVICE,
|
||||
SUPPLEMENTAL_PROCESS_SERVICE,
|
||||
//@hide: ATTESTATION_VERIFICATION_SERVICE,
|
||||
//@hide: SAFETY_CENTER_SERVICE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -5738,6 +5739,15 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String INCREMENTAL_SERVICE = "incremental";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve an
|
||||
* {@link android.security.attestationverification.AttestationVerificationManager}.
|
||||
* @see #getSystemService(String)
|
||||
* @see android.security.attestationverification.AttestationVerificationManager
|
||||
* @hide
|
||||
*/
|
||||
public static final String ATTESTATION_VERIFICATION_SERVICE = "attestation_verification";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve an
|
||||
* {@link android.security.FileIntegrityManager}.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.security.attestationverification;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable AttestationProfile;
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.security.attestationverification;
|
||||
|
||||
import static android.security.attestationverification.AttestationVerificationManager.PROFILE_APP_DEFINED;
|
||||
import static android.security.attestationverification.AttestationVerificationManager.PROFILE_UNKNOWN;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcelable;
|
||||
import android.security.attestationverification.AttestationVerificationManager.AttestationProfileId;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.DataClass;
|
||||
|
||||
|
||||
/**
|
||||
* An attestation profile defining the security requirements for verifying the attestation of a
|
||||
* remote compute environment.
|
||||
*
|
||||
* <p>This class is immutable and thread-safe. When checking this profile against an expected
|
||||
* profile, it is recommended to construct the expected profile and compare them with {@code
|
||||
* equals()}.
|
||||
*
|
||||
* @hide
|
||||
* @see AttestationVerificationManager
|
||||
*/
|
||||
@DataClass(
|
||||
genConstructor = false,
|
||||
genEqualsHashCode = true
|
||||
)
|
||||
public final class AttestationProfile implements Parcelable {
|
||||
|
||||
private static final String TAG = "AVF";
|
||||
|
||||
/**
|
||||
* The ID of a system-defined attestation profile.
|
||||
*
|
||||
* See constants in {@link AttestationVerificationManager} prefixed with {@code PROFILE_}. If
|
||||
* this has the value of {@link AttestationVerificationManager#PROFILE_APP_DEFINED}, then the
|
||||
* packageName and profileName are non-null.
|
||||
*/
|
||||
@AttestationProfileId
|
||||
private final int mAttestationProfileId;
|
||||
|
||||
/**
|
||||
* The package name of a app-defined attestation profile.
|
||||
*
|
||||
* This value will be null unless the value of attestationProfileId is {@link
|
||||
* AttestationVerificationManager#PROFILE_APP_DEFINED}.
|
||||
*/
|
||||
@Nullable
|
||||
private final String mPackageName;
|
||||
|
||||
|
||||
/**
|
||||
* The name of an app-defined attestation profile.
|
||||
*
|
||||
* This value will be null unless the value of attestationProfileId is {@link
|
||||
* AttestationVerificationManager#PROFILE_APP_DEFINED}.
|
||||
*/
|
||||
@Nullable
|
||||
private final String mProfileName;
|
||||
|
||||
private AttestationProfile(
|
||||
@AttestationProfileId int attestationProfileId,
|
||||
@Nullable String packageName,
|
||||
@Nullable String profileName) {
|
||||
mAttestationProfileId = attestationProfileId;
|
||||
mPackageName = packageName;
|
||||
mProfileName = profileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a profile with the given id.
|
||||
*
|
||||
* <p>This constructor is for specifying a profile which is defined by the system. These are
|
||||
* available as constants in the {@link AttestationVerificationManager} class prefixed with
|
||||
* {@code PROFILE_}.
|
||||
*
|
||||
* @param attestationProfileId the ID of the system-defined profile
|
||||
* @throws IllegalArgumentException when called with
|
||||
* {@link AttestationVerificationManager#PROFILE_APP_DEFINED}
|
||||
* (use {@link #AttestationProfile(String, String)})
|
||||
*/
|
||||
public AttestationProfile(@AttestationProfileId int attestationProfileId) {
|
||||
this(attestationProfileId, null, null);
|
||||
if (attestationProfileId == PROFILE_APP_DEFINED) {
|
||||
throw new IllegalArgumentException("App-defined profiles must be specified with the "
|
||||
+ "constructor AttestationProfile#constructor(String, String)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a profile with the given package name and profile name.
|
||||
*
|
||||
* <p>This constructor is for specifying a profile defined by an app. The packageName must
|
||||
* match the package name of the app that defines the profile (as specified in the {@code
|
||||
* package} attribute of the {@code
|
||||
* <manifest>} tag in the app's manifest. The profile name matches the {@code name} attribute
|
||||
* of the {@code <attestation-profile>} tag.
|
||||
*
|
||||
* <p>Apps must declare profiles in their manifest as an {@code <attestation-profile>} element.
|
||||
* However, this constructor does not verify that such a profile exists. If the profile does not
|
||||
* exist, verifications will fail.
|
||||
*
|
||||
* @param packageName the package name of the app defining the profile
|
||||
* @param profileName the name of the profile
|
||||
*/
|
||||
public AttestationProfile(@NonNull String packageName, @NonNull String profileName) {
|
||||
this(PROFILE_APP_DEFINED, packageName, profileName);
|
||||
if (packageName == null || profileName == null) {
|
||||
throw new IllegalArgumentException("Both packageName and profileName must be non-null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (mAttestationProfileId == PROFILE_APP_DEFINED) {
|
||||
return "AttestationProfile(package=" + mPackageName + ", name=" + mProfileName + ")";
|
||||
} else {
|
||||
String humanReadableProfileId;
|
||||
switch (mAttestationProfileId) {
|
||||
case PROFILE_UNKNOWN:
|
||||
humanReadableProfileId = "PROFILE_UNKNOWN";
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "ERROR: Missing case in AttestationProfile#toString");
|
||||
humanReadableProfileId = "ERROR";
|
||||
}
|
||||
return "AttestationProfile(" + humanReadableProfileId + "/" + mAttestationProfileId
|
||||
+ ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.23.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/security
|
||||
// /attestationverification/AttestationProfile.java
|
||||
//
|
||||
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
|
||||
// Settings > Editor > Code Style > Formatter Control
|
||||
//@formatter:off
|
||||
|
||||
|
||||
/**
|
||||
* The ID of a system-defined attestation profile.
|
||||
*
|
||||
* See constants in {@link AttestationVerificationManager} prefixed with {@code PROFILE_}. If
|
||||
* this has the value of {@link AttestationVerificationManager#PROFILE_APP_DEFINED}, then the
|
||||
* packageName and profileName are non-null.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @AttestationProfileId int getAttestationProfileId() {
|
||||
return mAttestationProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The package name of a app-defined attestation profile.
|
||||
*
|
||||
* This value will be null unless the value of attestationProfileId is {@link
|
||||
* AttestationVerificationManager#PROFILE_APP_DEFINED}.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @Nullable String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of an app-defined attestation profile.
|
||||
*
|
||||
* This value will be null unless the value of attestationProfileId is {@link
|
||||
* AttestationVerificationManager#PROFILE_APP_DEFINED}.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @Nullable String getProfileName() {
|
||||
return mProfileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public boolean equals(@Nullable Object o) {
|
||||
// You can override field equality logic by defining either of the methods like:
|
||||
// boolean fieldNameEquals(AttestationProfile other) { ... }
|
||||
// boolean fieldNameEquals(FieldType otherValue) { ... }
|
||||
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
@SuppressWarnings("unchecked")
|
||||
AttestationProfile that = (AttestationProfile) o;
|
||||
//noinspection PointlessBooleanExpression
|
||||
return true
|
||||
&& mAttestationProfileId == that.mAttestationProfileId
|
||||
&& java.util.Objects.equals(mPackageName, that.mPackageName)
|
||||
&& java.util.Objects.equals(mProfileName, that.mProfileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int hashCode() {
|
||||
// You can override field hashCode logic by defining methods like:
|
||||
// int fieldNameHashCode() { ... }
|
||||
|
||||
int _hash = 1;
|
||||
_hash = 31 * _hash + mAttestationProfileId;
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mProfileName);
|
||||
return _hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
byte flg = 0;
|
||||
if (mPackageName != null) flg |= 0x2;
|
||||
if (mProfileName != null) flg |= 0x4;
|
||||
dest.writeByte(flg);
|
||||
dest.writeInt(mAttestationProfileId);
|
||||
if (mPackageName != null) dest.writeString(mPackageName);
|
||||
if (mProfileName != null) dest.writeString(mProfileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
/** @hide */
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ AttestationProfile(@NonNull android.os.Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
byte flg = in.readByte();
|
||||
int attestationProfileId = in.readInt();
|
||||
String packageName = (flg & 0x2) == 0 ? null : in.readString();
|
||||
String profileName = (flg & 0x4) == 0 ? null : in.readString();
|
||||
|
||||
this.mAttestationProfileId = attestationProfileId;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
AttestationProfileId.class, null, mAttestationProfileId);
|
||||
this.mPackageName = packageName;
|
||||
this.mProfileName = profileName;
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<AttestationProfile> CREATOR
|
||||
= new Parcelable.Creator<AttestationProfile>() {
|
||||
@Override
|
||||
public AttestationProfile[] newArray(int size) {
|
||||
return new AttestationProfile[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttestationProfile createFromParcel(@NonNull android.os.Parcel in) {
|
||||
return new AttestationProfile(in);
|
||||
}
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1633629498403L,
|
||||
codegenVersion = "1.0.23",
|
||||
sourceFile = "frameworks/base/core/java/android/security/attestationverification/AttestationProfile.java",
|
||||
inputSignatures = "private static final java.lang.String TAG\nprivate final @android.security.attestationverification.AttestationVerificationManager.AttestationProfileId int mAttestationProfileId\nprivate final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mProfileName\npublic @java.lang.Override java.lang.String toString()\nclass AttestationProfile extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genEqualsHashCode=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
//@formatter:on
|
||||
// End of generated code
|
||||
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.security.attestationverification;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.CheckResult;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Provides methods for verifying that attestations from remote compute environments meet minimum
|
||||
* security requirements specified by attestation profiles.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemService(Context.ATTESTATION_VERIFICATION_SERVICE)
|
||||
public class AttestationVerificationManager {
|
||||
|
||||
/**
|
||||
* Verifies that {@code attestation} describes a computing environment that meets the
|
||||
* requirements of {@code profile}, {@code localBindingType}, and {@code requirements}.
|
||||
*
|
||||
* <p>This method verifies that at least one system-registered {@linkplain
|
||||
* AttestationVerificationService attestation verifier} associated with {@code profile} and
|
||||
* {@code localBindingType} has verified that {@code attestation} attests that the remote
|
||||
* environment matching the local binding data (determined by {@code localBindingType}) in
|
||||
* {@code requirements} meets the requirements of the profile.
|
||||
*
|
||||
* <p>For successful verification, the {@code requirements} bundle must contain locally-known
|
||||
* data which must match {@code attestation}. The required data in the bundle is defined by the
|
||||
* {@code localBindingType} (see documentation for the type). Verifiers will fail to verify the
|
||||
* attestation if the bundle contains unsupported data.
|
||||
*
|
||||
* <p>The {@code localBindingType} specifies how {@code attestation} is bound to a local
|
||||
* secure channel endpoint or similar connection with the target remote environment described by
|
||||
* the attestation. The binding is expected to be related to a cryptographic protocol, and each
|
||||
* binding type requires specific arguments to be present in the {@code requirements} bundle. It
|
||||
* is this binding to something known locally that ensures an attestation is not only valid, but
|
||||
* is also associated with a particular connection.
|
||||
*
|
||||
* <p>The {@code callback} is called with a result and {@link VerificationToken} (which may be
|
||||
* null). The result is an integer (see constants in this class with the prefix {@code RESULT_}.
|
||||
* The result is {@link #RESULT_SUCCESS} when at least one verifier has passed its checks. The
|
||||
* token may be used in calls to other parts of the system.
|
||||
*
|
||||
* <p>It's expected that a verifier will be able to decode and understand the passed values,
|
||||
* otherwise fail to verify. {@code attestation} should contain some type data to prevent parse
|
||||
* errors.
|
||||
*
|
||||
* <p>The values put into the {@code requirements} Bundle depend on the {@code
|
||||
* localBindingType} used.
|
||||
*
|
||||
* @param profile the attestation profile which defines the security requirements which
|
||||
* must be met by the environment described by {@code attestation}
|
||||
* @param localBindingType the type of the local binding data; see constants in this class with
|
||||
* the prefix {@code TYPE_}
|
||||
* @param requirements a {@link Bundle} containing locally-known data which must match
|
||||
* {@code attestation}
|
||||
* @param attestation attestation data which describes a remote computing environment
|
||||
* @param executor {@code callback} will be executed on this executor
|
||||
* @param callback will be called with the results of the verification
|
||||
* @see AttestationVerificationService
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE)
|
||||
public void verifyAttestation(
|
||||
@NonNull AttestationProfile profile,
|
||||
@LocalBindingType int localBindingType,
|
||||
@NonNull Bundle requirements,
|
||||
@NonNull byte[] attestation,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BiConsumer<@VerificationResult Integer, VerificationToken> callback) {
|
||||
executor.execute(() -> callback.accept(RESULT_UNKNOWN, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that {@code token} is a valid token, returning the result contained in valid
|
||||
* tokens.
|
||||
*
|
||||
* <p>This verifies that the token was issued by the platform and thus the system verified
|
||||
* attestation data against the specified {@code profile}, {@code localBindingType}, and {@code
|
||||
* requirements}. The value returned by this method is the same as the one originally returned
|
||||
* when the token was generated. Callers of this method should not trust the provider of the
|
||||
* token to also specify the profile, local binding type, or requirements, but instead have
|
||||
* their own security requirements about these arguments.
|
||||
*
|
||||
* <p>This method, in contrast to {@code verifyAttestation}, executes synchronously and only
|
||||
* checks that a previous verification succeeded. This allows callers to pass the token to
|
||||
* others, including system APIs, without those components needing to re-verify the attestation
|
||||
* data, an operation which can take several seconds.
|
||||
*
|
||||
* <p>When {@code maximumAge} is not specified (null), this method verifies the token was
|
||||
* generated in the past hour. Otherwise, it verifies the token was generated between now and
|
||||
* {@code maximumAge} ago. The maximum value of {@code maximumAge} is one hour; specifying a
|
||||
* duration greater than one hour will result in an {@link IllegalArgumentException}.
|
||||
*
|
||||
* @param profile the attestation profile which must be in the token
|
||||
* @param localBindingType the local binding type which must be in the token
|
||||
* @param requirements the requirements which must be in the token
|
||||
* @param token the token to be verified
|
||||
* @param maximumAge the maximum age to accept for the token
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE)
|
||||
@CheckResult
|
||||
@VerificationResult
|
||||
public int verifyToken(
|
||||
@NonNull AttestationProfile profile,
|
||||
@LocalBindingType int localBindingType,
|
||||
@NonNull Bundle requirements,
|
||||
@NonNull VerificationToken token,
|
||||
@Nullable java.time.Duration maximumAge) {
|
||||
return RESULT_UNKNOWN;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public AttestationVerificationManager() {
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
prefix = {"PROFILE_"},
|
||||
value = {
|
||||
PROFILE_UNKNOWN,
|
||||
PROFILE_APP_DEFINED,
|
||||
PROFILE_SELF_TRUSTED,
|
||||
PROFILE_PEER_DEVICE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface AttestationProfileId {
|
||||
}
|
||||
|
||||
/**
|
||||
* The profile is unknown because it is a profile unknown to this version of the SDK.
|
||||
*/
|
||||
public static final int PROFILE_UNKNOWN = 0;
|
||||
|
||||
/** The profile is defined by an app. */
|
||||
public static final int PROFILE_APP_DEFINED = 1;
|
||||
|
||||
/**
|
||||
* A system-defined profile which verifies that the attesting environment can create an
|
||||
* attestation with the same root certificate as the verifying device with a matching
|
||||
* attestation challenge.
|
||||
*
|
||||
* This profile is intended to be used only for testing.
|
||||
*/
|
||||
public static final int PROFILE_SELF_TRUSTED = 2;
|
||||
|
||||
/**
|
||||
* A system-defined profile which verifies that the attesting environment environment is similar
|
||||
* to the current device in terms of security model and security configuration. This category is
|
||||
* fairly broad and most securely configured Android devices should qualify, along with a
|
||||
* variety of non-Android devices.
|
||||
*/
|
||||
public static final int PROFILE_PEER_DEVICE = 3;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
prefix = {"TYPE_"},
|
||||
value = {
|
||||
TYPE_UNKNOWN,
|
||||
TYPE_APP_DEFINED,
|
||||
TYPE_PUBLIC_KEY,
|
||||
TYPE_CHALLENGE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LocalBindingType {
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the local binding data is unknown because it is a type unknown to this version of
|
||||
* the SDK.
|
||||
*/
|
||||
public static final int TYPE_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* A local binding type for app-defined profiles which use local binding data which does not
|
||||
* match any of the existing system-defined types.
|
||||
*/
|
||||
public static final int TYPE_APP_DEFINED = 1;
|
||||
|
||||
/**
|
||||
* A local binding type where the attestation is bound to a public key negotiated and
|
||||
* authenticated to a public key.
|
||||
*
|
||||
* <p>When using this type, the {@code requirements} bundle contains values for:
|
||||
* <ul>
|
||||
* <li>{@link #PARAM_PUBLIC_KEY}
|
||||
* <li>{@link #PARAM_ID}: identifying the remote environment, optional
|
||||
* </ul>
|
||||
*/
|
||||
public static final int TYPE_PUBLIC_KEY = 2;
|
||||
|
||||
/**
|
||||
* A local binding type where the attestation is bound to a challenge.
|
||||
*
|
||||
* <p>When using this type, the {@code requirements} bundle contains values for:
|
||||
* <ul>
|
||||
* <li>{@link #PARAM_CHALLENGE}: containing the challenge
|
||||
* </ul>
|
||||
*/
|
||||
public static final int TYPE_CHALLENGE = 3;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
prefix = {"RESULT_"},
|
||||
value = {
|
||||
RESULT_UNKNOWN,
|
||||
RESULT_SUCCESS,
|
||||
RESULT_FAILURE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
|
||||
public @interface VerificationResult {
|
||||
}
|
||||
|
||||
/** The result of the verification is unknown because it has a value unknown to this SDK. */
|
||||
public static final int RESULT_UNKNOWN = 0;
|
||||
|
||||
/** The result of the verification was successful. */
|
||||
public static final int RESULT_SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* The result of the attestation verification was failure. The attestation could not be
|
||||
* verified.
|
||||
*/
|
||||
public static final int RESULT_FAILURE = 2;
|
||||
|
||||
/**
|
||||
* Requirements bundle parameter key for a public key, a byte array.
|
||||
*
|
||||
* <p>This should contain the encoded key bytes according to the ASN.1 type
|
||||
* {@code SubjectPublicKeyInfo} defined in the X.509 standard, the same as a call to {@link
|
||||
* java.security.spec.X509EncodedKeySpec#getEncoded()} would produce.
|
||||
*
|
||||
* @see Bundle#putByteArray(String, byte[])
|
||||
*/
|
||||
public static final String PARAM_PUBLIC_KEY = "localbinding.public_key";
|
||||
|
||||
/** Requirements bundle parameter key for an ID, String. */
|
||||
public static final String PARAM_ID = "localbinding.id";
|
||||
|
||||
/** Requirements bundle parameter for a challenge. */
|
||||
public static final String PARAM_CHALLENGE = "localbinding.challenge";
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.security.attestationverification;
|
||||
|
||||
import android.annotation.CheckResult;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Service;
|
||||
import android.os.Bundle;
|
||||
import android.security.attestationverification.AttestationVerificationManager.VerificationResult;
|
||||
|
||||
/**
|
||||
* A verifier which can be implemented by apps to verify an attestation (as described in {@link
|
||||
* AttestationVerificationManager}).
|
||||
*
|
||||
* In the manifest for this service, specify the profile and local binding type this verifier
|
||||
* supports. Create a new service for each combination of profile & local binding type that your app
|
||||
* supports. Each service must declare an {@code intent-filter} action of {@link #SERVICE_INTERFACE}
|
||||
* and permission of {@link android.Manifest.permission#BIND_ATTESTATION_VERIFICATION_SERVICE}.
|
||||
*
|
||||
* <p>Example:
|
||||
* {@code
|
||||
* <pre>
|
||||
* <service android:name=".MyAttestationVerificationService"
|
||||
* android:permission="android.permission.BIND_ATTESTATION_VERIFICATION_SERVICE"
|
||||
* android:exported="true">
|
||||
* <intent-filter>
|
||||
* <action
|
||||
* android:name="android.security.attestationverification.AttestationVerificationService" />
|
||||
* </intent-filter>
|
||||
* <meta-data android:name="android.security.attestationverification.PROFILE_ID"
|
||||
* android:value="PROFILE_PLACEHOLDER_0" />
|
||||
* <meta-data android:name="android.security.attestationverification.LOCAL_BINDING_TYPE"
|
||||
* android:value="TYPE_PLACEHOLDER_0" />
|
||||
* </service>
|
||||
* </pre>
|
||||
* }
|
||||
*
|
||||
* <p>For app-defined profiles, an example of the {@code <meta-data>}:
|
||||
* {@code
|
||||
* <pre>
|
||||
* <meta-data android:name="android.security.attestation.PROFILE_PACKAGE_NAME"
|
||||
* android:value="com.example" />
|
||||
* <meta-data android:name="android.security.attestation.PROFILE_NAME"
|
||||
* android:value="com.example.profile.PROFILE_FOO" />
|
||||
* </pre>
|
||||
* }
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class AttestationVerificationService extends Service {
|
||||
|
||||
/**
|
||||
* An intent action for a service to be bound and act as an attestation verifier.
|
||||
*
|
||||
* <p>The app will be kept alive for a short duration between verification calls after which
|
||||
* the system will unbind from this service making the app eligible for cleanup.
|
||||
*
|
||||
* <p>The service must also require permission
|
||||
* {@link android.Manifest.permission#BIND_ATTESTATION_VERIFICATION_SERVICE}.
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.security.attestationverification.AttestationVerificationService";
|
||||
|
||||
/**
|
||||
* Verifies that {@code attestation} attests that the device identified by the local binding
|
||||
* data in {@code requirements} meets the minimum requirements of this verifier for this
|
||||
* verifier's profile.
|
||||
*
|
||||
* <p>Called by the system to verify an attestation.
|
||||
*
|
||||
* <p>The data passed into this method comes directly from apps and should be treated as
|
||||
* potentially dangerous user input.
|
||||
*
|
||||
* @param requirements a {@link Bundle} containing locally-known data which must match {@code
|
||||
* attestation}
|
||||
* @param attestation the attestation to verify
|
||||
* @return whether the verification passed
|
||||
* @see AttestationVerificationManager#verifyAttestation(AttestationProfile, int, Bundle,
|
||||
* byte[], java.util.concurrent.Executor, java.util.function.BiConsumer)
|
||||
*/
|
||||
@CheckResult
|
||||
@VerificationResult
|
||||
public abstract int onVerifyPeerDeviceAttestation(
|
||||
@NonNull Bundle requirements,
|
||||
@NonNull byte[] attestation);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.security.attestationverification;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable VerificationToken;
|
||||
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.security.attestationverification;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.security.attestationverification.AttestationVerificationManager.LocalBindingType;
|
||||
import android.security.attestationverification.AttestationVerificationManager.VerificationResult;
|
||||
|
||||
import com.android.internal.util.DataClass;
|
||||
import com.android.internal.util.Parcelling;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInstant;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Token representing the result of an attestation verification, which can be passed to other parts
|
||||
* of the OS or other apps as proof of the verification.
|
||||
*
|
||||
* Tokens are only valid within the same UID (which means within a single app unless the deprecated
|
||||
* android:sharedUserId manifest value is used).
|
||||
*
|
||||
* @hide
|
||||
* @see Bundle#putParcelable(String, Parcelable)
|
||||
*/
|
||||
@DataClass(
|
||||
genConstructor = false,
|
||||
genHiddenBuilder = true
|
||||
)
|
||||
public final class VerificationToken implements Parcelable {
|
||||
|
||||
/**
|
||||
* The attestation profile which was used to perform the verification.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
private final AttestationProfile mAttestationProfile;
|
||||
|
||||
/**
|
||||
* The local binding type of the local binding data used to perform the verification.
|
||||
* @hide
|
||||
*/
|
||||
@LocalBindingType
|
||||
private final int mLocalBindingType;
|
||||
|
||||
/**
|
||||
* The requirements used to perform the verification.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
private final Bundle mRequirements;
|
||||
|
||||
/**
|
||||
* The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
|
||||
* byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
|
||||
* accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
|
||||
* value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
|
||||
* Duration)} to verify a valid token and it will return this value.
|
||||
*
|
||||
* If the token is valid, this value is returned directly by {#verifyToken}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@VerificationResult
|
||||
private final int mVerificationResult;
|
||||
|
||||
/**
|
||||
* Time when the token was generated, set by the system.
|
||||
*/
|
||||
@NonNull
|
||||
@DataClass.ParcelWith(ForInstant.class)
|
||||
private final java.time.Instant mVerificationTime;
|
||||
|
||||
/**
|
||||
* A Hash-based message authentication code used to verify the contents and authenticity of the
|
||||
* rest of the token. The hash is created using a secret key known only to the system server.
|
||||
* When verifying the token, the system re-hashes the token and verifies the generated HMAC is
|
||||
* the same.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
private final byte[] mHmac;
|
||||
|
||||
/**
|
||||
* The UID of the process which called {@code verifyAttestation} to create the token, as
|
||||
* returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
|
||||
* of calling process does not match this value. This ensures that tokens cannot be shared
|
||||
* between UIDs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private int mUid;
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.23.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/security/attestationverification/VerificationToken.java
|
||||
//
|
||||
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
|
||||
// Settings > Editor > Code Style > Formatter Control
|
||||
//@formatter:off
|
||||
|
||||
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ VerificationToken(
|
||||
@NonNull AttestationProfile attestationProfile,
|
||||
@LocalBindingType int localBindingType,
|
||||
@NonNull Bundle requirements,
|
||||
@VerificationResult int verificationResult,
|
||||
@NonNull java.time.Instant verificationTime,
|
||||
@NonNull byte[] hmac,
|
||||
int uid) {
|
||||
this.mAttestationProfile = attestationProfile;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mAttestationProfile);
|
||||
this.mLocalBindingType = localBindingType;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
LocalBindingType.class, null, mLocalBindingType);
|
||||
this.mRequirements = requirements;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mRequirements);
|
||||
this.mVerificationResult = verificationResult;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
VerificationResult.class, null, mVerificationResult);
|
||||
this.mVerificationTime = verificationTime;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mVerificationTime);
|
||||
this.mHmac = hmac;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHmac);
|
||||
this.mUid = uid;
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
/**
|
||||
* The attestation profile which was used to perform the verification.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull AttestationProfile getAttestationProfile() {
|
||||
return mAttestationProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* The local binding type of the local binding data used to perform the verification.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @LocalBindingType int getLocalBindingType() {
|
||||
return mLocalBindingType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The requirements used to perform the verification.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Bundle getRequirements() {
|
||||
return mRequirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
|
||||
* byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
|
||||
* accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
|
||||
* value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
|
||||
* Duration)} to verify a valid token and it will return this value.
|
||||
*
|
||||
* If the token is valid, this value is returned directly by {#verifyToken}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @VerificationResult int getVerificationResult() {
|
||||
return mVerificationResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time when the token was generated, set by the system.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull java.time.Instant getVerificationTime() {
|
||||
return mVerificationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Hash-based message authentication code used to verify the contents and authenticity of the
|
||||
* rest of the token. The hash is created using a secret key known only to the system server.
|
||||
* When verifying the token, the system re-hashes the token and verifies the generated HMAC is
|
||||
* the same.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull byte[] getHmac() {
|
||||
return mHmac;
|
||||
}
|
||||
|
||||
/**
|
||||
* The UID of the process which called {@code verifyAttestation} to create the token, as
|
||||
* returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
|
||||
* of calling process does not match this value. This ensures that tokens cannot be shared
|
||||
* between UIDs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public int getUid() {
|
||||
return mUid;
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
static Parcelling<java.time.Instant> sParcellingForVerificationTime =
|
||||
Parcelling.Cache.get(
|
||||
ForInstant.class);
|
||||
static {
|
||||
if (sParcellingForVerificationTime == null) {
|
||||
sParcellingForVerificationTime = Parcelling.Cache.put(
|
||||
new ForInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
dest.writeTypedObject(mAttestationProfile, flags);
|
||||
dest.writeInt(mLocalBindingType);
|
||||
dest.writeBundle(mRequirements);
|
||||
dest.writeInt(mVerificationResult);
|
||||
sParcellingForVerificationTime.parcel(mVerificationTime, dest, flags);
|
||||
dest.writeByteArray(mHmac);
|
||||
dest.writeInt(mUid);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
/** @hide */
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ VerificationToken(@NonNull android.os.Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
AttestationProfile attestationProfile = (AttestationProfile) in.readTypedObject(AttestationProfile.CREATOR);
|
||||
int localBindingType = in.readInt();
|
||||
Bundle requirements = in.readBundle();
|
||||
int verificationResult = in.readInt();
|
||||
java.time.Instant verificationTime = sParcellingForVerificationTime.unparcel(in);
|
||||
byte[] hmac = in.createByteArray();
|
||||
int uid = in.readInt();
|
||||
|
||||
this.mAttestationProfile = attestationProfile;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mAttestationProfile);
|
||||
this.mLocalBindingType = localBindingType;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
LocalBindingType.class, null, mLocalBindingType);
|
||||
this.mRequirements = requirements;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mRequirements);
|
||||
this.mVerificationResult = verificationResult;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
VerificationResult.class, null, mVerificationResult);
|
||||
this.mVerificationTime = verificationTime;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mVerificationTime);
|
||||
this.mHmac = hmac;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHmac);
|
||||
this.mUid = uid;
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<VerificationToken> CREATOR
|
||||
= new Parcelable.Creator<VerificationToken>() {
|
||||
@Override
|
||||
public VerificationToken[] newArray(int size) {
|
||||
return new VerificationToken[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerificationToken createFromParcel(@NonNull android.os.Parcel in) {
|
||||
return new VerificationToken(in);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A builder for {@link VerificationToken}
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@DataClass.Generated.Member
|
||||
public static final class Builder {
|
||||
|
||||
private @NonNull AttestationProfile mAttestationProfile;
|
||||
private @LocalBindingType int mLocalBindingType;
|
||||
private @NonNull Bundle mRequirements;
|
||||
private @VerificationResult int mVerificationResult;
|
||||
private @NonNull java.time.Instant mVerificationTime;
|
||||
private @NonNull byte[] mHmac;
|
||||
private int mUid;
|
||||
|
||||
private long mBuilderFieldsSet = 0L;
|
||||
|
||||
/**
|
||||
* Creates a new Builder.
|
||||
*
|
||||
* @param attestationProfile
|
||||
* The attestation profile which was used to perform the verification.
|
||||
* @param localBindingType
|
||||
* The local binding type of the local binding data used to perform the verification.
|
||||
* @param requirements
|
||||
* The requirements used to perform the verification.
|
||||
* @param verificationResult
|
||||
* The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
|
||||
* byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
|
||||
* accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
|
||||
* value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
|
||||
* Duration)} to verify a valid token and it will return this value.
|
||||
*
|
||||
* If the token is valid, this value is returned directly by {#verifyToken}.
|
||||
* @param verificationTime
|
||||
* Time when the token was generated, set by the system.
|
||||
* @param hmac
|
||||
* A Hash-based message authentication code used to verify the contents and authenticity of the
|
||||
* rest of the token. The hash is created using a secret key known only to the system server.
|
||||
* When verifying the token, the system re-hashes the token and verifies the generated HMAC is
|
||||
* the same.
|
||||
* @param uid
|
||||
* The UID of the process which called {@code verifyAttestation} to create the token, as
|
||||
* returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
|
||||
* of calling process does not match this value. This ensures that tokens cannot be shared
|
||||
* between UIDs.
|
||||
*/
|
||||
public Builder(
|
||||
@NonNull AttestationProfile attestationProfile,
|
||||
@LocalBindingType int localBindingType,
|
||||
@NonNull Bundle requirements,
|
||||
@VerificationResult int verificationResult,
|
||||
@NonNull java.time.Instant verificationTime,
|
||||
@NonNull byte[] hmac,
|
||||
int uid) {
|
||||
mAttestationProfile = attestationProfile;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mAttestationProfile);
|
||||
mLocalBindingType = localBindingType;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
LocalBindingType.class, null, mLocalBindingType);
|
||||
mRequirements = requirements;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mRequirements);
|
||||
mVerificationResult = verificationResult;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
VerificationResult.class, null, mVerificationResult);
|
||||
mVerificationTime = verificationTime;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mVerificationTime);
|
||||
mHmac = hmac;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHmac);
|
||||
mUid = uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* The attestation profile which was used to perform the verification.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setAttestationProfile(@NonNull AttestationProfile value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x1;
|
||||
mAttestationProfile = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The local binding type of the local binding data used to perform the verification.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setLocalBindingType(@LocalBindingType int value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x2;
|
||||
mLocalBindingType = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The requirements used to perform the verification.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setRequirements(@NonNull Bundle value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x4;
|
||||
mRequirements = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
|
||||
* byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
|
||||
* accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
|
||||
* value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
|
||||
* Duration)} to verify a valid token and it will return this value.
|
||||
*
|
||||
* If the token is valid, this value is returned directly by {#verifyToken}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setVerificationResult(@VerificationResult int value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x8;
|
||||
mVerificationResult = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time when the token was generated, set by the system.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setVerificationTime(@NonNull java.time.Instant value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x10;
|
||||
mVerificationTime = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Hash-based message authentication code used to verify the contents and authenticity of the
|
||||
* rest of the token. The hash is created using a secret key known only to the system server.
|
||||
* When verifying the token, the system re-hashes the token and verifies the generated HMAC is
|
||||
* the same.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setHmac(@NonNull byte... value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x20;
|
||||
mHmac = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The UID of the process which called {@code verifyAttestation} to create the token, as
|
||||
* returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
|
||||
* of calling process does not match this value. This ensures that tokens cannot be shared
|
||||
* between UIDs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setUid(int value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x40;
|
||||
mUid = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds the instance. This builder should not be touched after calling this! */
|
||||
public @NonNull VerificationToken build() {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x80; // Mark builder used
|
||||
|
||||
VerificationToken o = new VerificationToken(
|
||||
mAttestationProfile,
|
||||
mLocalBindingType,
|
||||
mRequirements,
|
||||
mVerificationResult,
|
||||
mVerificationTime,
|
||||
mHmac,
|
||||
mUid);
|
||||
return o;
|
||||
}
|
||||
|
||||
private void checkNotUsed() {
|
||||
if ((mBuilderFieldsSet & 0x80) != 0) {
|
||||
throw new IllegalStateException(
|
||||
"This Builder should not be reused. Use a new Builder instance instead");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1633629747234L,
|
||||
codegenVersion = "1.0.23",
|
||||
sourceFile = "frameworks/base/core/java/android/security/attestationverification/VerificationToken.java",
|
||||
inputSignatures = "private final @android.annotation.NonNull android.security.attestationverification.AttestationProfile mAttestationProfile\nprivate final @android.security.attestationverification.AttestationVerificationManager.LocalBindingType int mLocalBindingType\nprivate final @android.annotation.NonNull android.os.Bundle mRequirements\nprivate final @android.security.attestationverification.AttestationVerificationManager.VerificationResult int mVerificationResult\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) java.time.Instant mVerificationTime\nprivate final @android.annotation.NonNull byte[] mHmac\nprivate int mUid\nclass VerificationToken extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genHiddenBuilder=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
//@formatter:on
|
||||
// End of generated code
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
{@hide}
|
||||
</body>
|
||||
@@ -23,6 +23,7 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -306,5 +307,33 @@ public interface Parcelling<T> {
|
||||
return string == null ? null : UUID.fromString(string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Parcelling} for {@link Instant}.
|
||||
*
|
||||
* The minimum value of an instant uses a millisecond offset of about -3.15e19 which is
|
||||
* larger than Long.MIN_VALUE, so we can use Long.MIN_VALUE as a sentinel value to indicate
|
||||
* a null Instant.
|
||||
*/
|
||||
class ForInstant implements Parcelling<Instant> {
|
||||
|
||||
@Override
|
||||
public void parcel(Instant item, Parcel dest, int parcelFlags) {
|
||||
dest.writeLong(item == null ? Long.MIN_VALUE : item.getEpochSecond());
|
||||
dest.writeInt(item == null ? Integer.MIN_VALUE : item.getNano());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant unparcel(Parcel source) {
|
||||
long epochSecond = source.readLong();
|
||||
int afterNano = source.readInt();
|
||||
|
||||
if (epochSecond == Long.MIN_VALUE) {
|
||||
return null;
|
||||
} else {
|
||||
return Instant.ofEpochSecond(epochSecond, afterNano);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3470,6 +3470,23 @@
|
||||
<permission android:name="android.permission.UPDATE_FONTS"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows an application to use the AttestationVerificationService.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an application to export a AttestationVerificationService to verify attestations on
|
||||
behalf of AttestationVerificationManager for system-defined attestation profiles.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.VERIFY_ATTESTATION"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Must be required by any AttestationVerificationService to ensure that only the system can
|
||||
bind to it.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.BIND_ATTESTATION_VERIFICATION_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- ========================================= -->
|
||||
<!-- Permissions for special development tools -->
|
||||
<!-- ========================================= -->
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.internal.util;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInstant;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/** Tests for {@link Parcelling}. */
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(JUnit4.class)
|
||||
public class ParcellingTests {
|
||||
|
||||
private Parcel mParcel = Parcel.obtain();
|
||||
|
||||
@Test
|
||||
public void forInstant_normal() {
|
||||
testForInstant(Instant.ofEpochSecond(500L, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forInstant_minimum() {
|
||||
testForInstant(Instant.MIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forInstant_maximum() {
|
||||
testForInstant(Instant.MAX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forInstant_null() {
|
||||
testForInstant(null);
|
||||
}
|
||||
|
||||
private void testForInstant(Instant instant) {
|
||||
Parcelling<Instant> parcelling = new ForInstant();
|
||||
parcelling.parcel(instant, mParcel, 0);
|
||||
mParcel.setDataPosition(0);
|
||||
|
||||
Instant created = parcelling.unparcel(mParcel);
|
||||
|
||||
if (instant == null) {
|
||||
assertNull(created);
|
||||
} else {
|
||||
assertEquals(instant, created);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user