Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6379b09f authored by Guojing Yuan's avatar Guojing Yuan Committed by Android (Google) Code Review
Browse files

Merge "[AVF] Expose patch level check failure code" into main

parents 88d879f6 e855f084
Loading
Loading
Loading
Loading
+57 −45
Original line number Diff line number Diff line
@@ -79,9 +79,7 @@ public class AttestationVerificationManager {
     * 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.
     * null). The result is an integer (see constants in {@link VerificationResultFlags}).
     *
     * <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
@@ -108,7 +106,7 @@ public class AttestationVerificationManager {
            @NonNull Bundle requirements,
            @NonNull byte[] attestation,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull BiConsumer<@VerificationResult Integer, VerificationToken> callback) {
            @NonNull BiConsumer<@VerificationResultFlags Integer, VerificationToken> callback) {
        try {
            AndroidFuture<IVerificationResult> resultCallback = new AndroidFuture<>();
            resultCallback.thenAccept(result -> {
@@ -155,7 +153,7 @@ public class AttestationVerificationManager {
     */
    @RequiresPermission(Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE)
    @CheckResult
    @VerificationResult
    @VerificationResultFlags
    public int verifyToken(
            @NonNull AttestationProfile profile,
            @LocalBindingType int localBindingType,
@@ -280,30 +278,66 @@ public class AttestationVerificationManager {
     */
    public static final int TYPE_CHALLENGE = 3;

    /** @hide */
    @IntDef(
            prefix = {"RESULT_"},
    /**
     * Verification result returned from {@link #verifyAttestation}.
     *
     * A value of {@code 0} indicates success. Otherwise, a bit flag is set from first failing stage
     * below:
     * <ol>
     * <li> The received attestation's integrity (e.g. the certificate signatures) is validated.
     * If this fails, {@link #FLAG_FAILURE_CERTS} will be returned with all other bits unset.
     * <li> The local binding requirements are checked. If this fails,
     * {@link #FLAG_FAILURE_LOCAL_BINDING_REQUIREMENTS} is returned with all other bits unset.
     * <li> The profile requirements are checked. If this fails, a bit flag will be returned with
     * some of the these bits set to indicate the type of profile requirement failure:
     * {@link #FLAG_FAILURE_UNSUPPORTED_PROFILE}, {@link #FLAG_FAILURE_KEYSTORE_REQUIREMENTS},
     * {@link #FLAG_FAILURE_BOOT_STATE}, and {@link #FLAG_FAILURE_PATCH_LEVEL_DIFF}.
     * </ol>
     *
     * Note: The reason of the failure must be not be provided to the remote device.
     *
     * @hide
     */
    @IntDef(flag = true, prefix = {"FLAG_FAILURE_"},
    value = {
                    RESULT_UNKNOWN,
                    RESULT_SUCCESS,
                    RESULT_FAILURE,
            FLAG_FAILURE_UNKNOWN,
            FLAG_FAILURE_UNSUPPORTED_PROFILE,
            FLAG_FAILURE_CERTS,
            FLAG_FAILURE_LOCAL_BINDING_REQUIREMENTS,
            FLAG_FAILURE_KEYSTORE_REQUIREMENTS,
            FLAG_FAILURE_BOOT_STATE,
            FLAG_FAILURE_PATCH_LEVEL_DIFF,
    })
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface VerificationResult {
    }
    @Retention(RetentionPolicy.SOURCE)
    public @interface VerificationResultFlags{}

    /** Flag: If there are unknown failures e.g. runtime exception. 0 = no, 1 = yes. */
    public static final int FLAG_FAILURE_UNKNOWN = 1;

    /** The result of the verification is unknown because it has a value unknown to this SDK. */
    public static final int RESULT_UNKNOWN = 0;
    /** Flag: If the AVF profile is supported. 0 = supported, 1 = not supported */
    public static final int FLAG_FAILURE_UNSUPPORTED_PROFILE = 1 << 1;

    /**
     * Flag: Result bit for certs verification e.g. loading, generating, parsing certs.
     * 0 = success, 1 = failure
     */
    public static final int FLAG_FAILURE_CERTS = 1 << 2;

    /** The result of the verification was successful. */
    public static final int RESULT_SUCCESS = 1;
    /** Flag: Result bit for local binding requirements verification. 0 = success, 1 = failure. */
    public static final int FLAG_FAILURE_LOCAL_BINDING_REQUIREMENTS = 1 << 3;

    /**
     * The result of the attestation verification was failure. The attestation could not be
     * verified.
     * Flag: Result bit for KeyStore requirements verification.
     * 0 = success, 1 = failure.
     */
    public static final int RESULT_FAILURE = 2;
    public static final int FLAG_FAILURE_KEYSTORE_REQUIREMENTS = 1 << 4;

    /** Flag: Result bit for boot state verification. 0 = success, 1 = failure */
    public static final int FLAG_FAILURE_BOOT_STATE = 1 << 5;

    /** Flag: Result bit for patch level diff checks. 0 = success, 1 = failure. */
    public static final int FLAG_FAILURE_PATCH_LEVEL_DIFF = 1 << 6;

    /**
     * Requirements bundle parameter key for a public key, a byte array.
@@ -351,26 +385,4 @@ public class AttestationVerificationManager {
        }
        return text + "(" + localBindingType + ")";
    }

    /** @hide */
    public static String verificationResultCodeToString(@VerificationResult int resultCode) {
        final String text;
        switch (resultCode) {
            case RESULT_UNKNOWN:
                text = "UNKNOWN";
                break;

            case RESULT_SUCCESS:
                text = "SUCCESS";
                break;

            case RESULT_FAILURE:
                text = "FAILURE";
                break;

            default:
                return Integer.toString(resultCode);
        }
        return text + "(" + resultCode + ")";
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.app.Service;
import android.os.Bundle;
import android.security.attestationverification.AttestationVerificationManager.VerificationResult;
import android.security.attestationverification.AttestationVerificationManager.VerificationResultFlags;

/**
 * A verifier which can be implemented by apps to verify an attestation (as described in {@link
@@ -93,7 +93,7 @@ public abstract class AttestationVerificationService extends Service {
     * byte[], java.util.concurrent.Executor, java.util.function.BiConsumer)
     */
    @CheckResult
    @VerificationResult
    @VerificationResultFlags
    public abstract int onVerifyPeerDeviceAttestation(
            @NonNull Bundle requirements,
            @NonNull byte[] attestation);
+63 −142

File changed.

Preview size limit exceeded, changes collapsed.

+4 −6
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.server.companion.securechannel;

import static android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS;

import android.annotation.NonNull;
import android.content.Context;
import android.os.Build;
@@ -498,7 +496,7 @@ public class SecureChannel {

    private void exchangeAttestation()
            throws IOException, GeneralSecurityException, BadHandleException, CryptoException {
        if (mVerificationResult == RESULT_SUCCESS) {
        if (mVerificationResult == 0) {
            Slog.d(TAG, "Remote attestation was already verified.");
            return;
        }
@@ -530,11 +528,11 @@ public class SecureChannel {
        sendMessage(MessageType.AVF_RESULT, verificationResult);
        byte[] remoteVerificationResult = readMessage(MessageType.AVF_RESULT);

        if (ByteBuffer.wrap(remoteVerificationResult).getInt() != RESULT_SUCCESS) {
        if (ByteBuffer.wrap(remoteVerificationResult).getInt() != 0) {
            throw new SecureChannelException("Remote device failed to verify local attestation.");
        }

        if (mVerificationResult != RESULT_SUCCESS) {
        if (mVerificationResult != 0) {
            throw new SecureChannelException("Failed to verify remote attestation.");
        }

@@ -549,7 +547,7 @@ public class SecureChannel {
            return false;
        }
        // Is authenticated
        return mPskVerified || mVerificationResult == RESULT_SUCCESS;
        return mPskVerified || mVerificationResult == 0;
    }

    // First byte indicates message type; 0 = CLIENT INIT, 1 = SERVER INIT
+9 −9
Original line number Diff line number Diff line
@@ -17,10 +17,10 @@
package com.android.server.security;

import static android.Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE;
import static android.security.attestationverification.AttestationVerificationManager.FLAG_FAILURE_CERTS;
import static android.security.attestationverification.AttestationVerificationManager.FLAG_FAILURE_UNSUPPORTED_PROFILE;
import static android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE;
import static android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -88,8 +88,8 @@ public class AttestationVerificationManagerService extends SystemService {
        public void verifyToken(VerificationToken token, ParcelDuration parcelDuration,
                AndroidFuture resultCallback) throws RemoteException {
            enforceUsePermission();
            // TODO(b/201696614): Implement
            resultCallback.complete(RESULT_UNKNOWN);

            throw new UnsupportedOperationException();
        }

        private void enforceUsePermission() {
@@ -123,9 +123,9 @@ public class AttestationVerificationManagerService extends SystemService {
            AttestationProfile profile, int localBindingType, Bundle requirements,
            byte[] attestation, AndroidFuture<IVerificationResult> resultCallback) {
        IVerificationResult result = new IVerificationResult();
        // TODO(b/201696614): Implement
        result.token = null;
        switch (profile.getAttestationProfileId()) {
        int profileId = profile.getAttestationProfileId();
        switch (profileId) {
            case PROFILE_SELF_TRUSTED:
                Slog.d(TAG, "Verifying Self Trusted profile.");
                try {
@@ -133,7 +133,7 @@ public class AttestationVerificationManagerService extends SystemService {
                            AttestationVerificationSelfTrustedVerifierForTesting.getInstance()
                                    .verifyAttestation(localBindingType, requirements, attestation);
                } catch (Throwable t) {
                    result.resultCode = RESULT_FAILURE;
                    result.resultCode = FLAG_FAILURE_CERTS;
                }
                break;
            case PROFILE_PEER_DEVICE:
@@ -142,8 +142,8 @@ public class AttestationVerificationManagerService extends SystemService {
                        localBindingType, requirements, attestation);
                break;
            default:
                Slog.d(TAG, "No profile found, defaulting.");
                result.resultCode = RESULT_UNKNOWN;
                Slog.e(TAG, "Profile [" + profileId + "] is not supported.");
                result.resultCode = FLAG_FAILURE_UNSUPPORTED_PROFILE;
        }
        resultCallback.complete(result);
    }
Loading