1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.security; 18 19 import static android.Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE; 20 import static android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE; 21 import static android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED; 22 import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE; 23 import static android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.Context; 28 import android.os.Bundle; 29 import android.os.IBinder; 30 import android.os.ParcelDuration; 31 import android.os.RemoteException; 32 import android.security.attestationverification.AttestationProfile; 33 import android.security.attestationverification.IAttestationVerificationManagerService; 34 import android.security.attestationverification.IVerificationResult; 35 import android.security.attestationverification.VerificationToken; 36 import android.text.TextUtils; 37 import android.util.ExceptionUtils; 38 import android.util.IndentingPrintWriter; 39 import android.util.Slog; 40 import android.util.TimeUtils; 41 42 import com.android.internal.infra.AndroidFuture; 43 import com.android.internal.util.DumpUtils; 44 import com.android.server.SystemService; 45 46 import java.io.FileDescriptor; 47 import java.io.PrintWriter; 48 import java.util.ArrayDeque; 49 50 /** 51 * A {@link SystemService} which provides functionality related to verifying attestations of 52 * (usually) remote computing environments. 53 * 54 * @hide 55 */ 56 public class AttestationVerificationManagerService extends SystemService { 57 58 private static final String TAG = "AVF"; 59 private static final int DUMP_EVENT_LOG_SIZE = 10; 60 private final AttestationVerificationPeerDeviceVerifier mPeerDeviceVerifier; 61 private final DumpLogger mDumpLogger = new DumpLogger(); 62 AttestationVerificationManagerService(final Context context)63 public AttestationVerificationManagerService(final Context context) throws Exception { 64 super(context); 65 mPeerDeviceVerifier = new AttestationVerificationPeerDeviceVerifier(context, mDumpLogger); 66 } 67 68 private final IBinder mService = new IAttestationVerificationManagerService.Stub() { 69 @Override 70 public void verifyAttestation( 71 AttestationProfile profile, 72 int localBindingType, 73 Bundle requirements, 74 byte[] attestation, 75 AndroidFuture resultCallback) throws RemoteException { 76 enforceUsePermission(); 77 try { 78 Slog.d(TAG, "verifyAttestation"); 79 verifyAttestationForAllVerifiers(profile, localBindingType, requirements, 80 attestation, resultCallback); 81 } catch (Throwable t) { 82 Slog.e(TAG, "failed to verify attestation", t); 83 throw ExceptionUtils.propagate(t, RemoteException.class); 84 } 85 } 86 87 @Override 88 public void verifyToken(VerificationToken token, ParcelDuration parcelDuration, 89 AndroidFuture resultCallback) throws RemoteException { 90 enforceUsePermission(); 91 // TODO(b/201696614): Implement 92 resultCallback.complete(RESULT_UNKNOWN); 93 } 94 95 private void enforceUsePermission() { 96 getContext().enforceCallingOrSelfPermission(USE_ATTESTATION_VERIFICATION_SERVICE, null); 97 } 98 99 @Override 100 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, 101 @Nullable String[] args) { 102 if (!android.security.Flags.dumpAttestationVerifications()) { 103 super.dump(fd, writer, args); 104 return; 105 } 106 107 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, writer)) return; 108 109 final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " "); 110 111 fout.print("AttestationVerificationManagerService"); 112 fout.println(); 113 fout.increaseIndent(); 114 115 fout.println("Event Log:"); 116 fout.increaseIndent(); 117 mDumpLogger.dumpTo(fout); 118 fout.decreaseIndent(); 119 } 120 }; 121 verifyAttestationForAllVerifiers( AttestationProfile profile, int localBindingType, Bundle requirements, byte[] attestation, AndroidFuture<IVerificationResult> resultCallback)122 private void verifyAttestationForAllVerifiers( 123 AttestationProfile profile, int localBindingType, Bundle requirements, 124 byte[] attestation, AndroidFuture<IVerificationResult> resultCallback) { 125 IVerificationResult result = new IVerificationResult(); 126 // TODO(b/201696614): Implement 127 result.token = null; 128 switch (profile.getAttestationProfileId()) { 129 case PROFILE_SELF_TRUSTED: 130 Slog.d(TAG, "Verifying Self Trusted profile."); 131 try { 132 result.resultCode = 133 AttestationVerificationSelfTrustedVerifierForTesting.getInstance() 134 .verifyAttestation(localBindingType, requirements, attestation); 135 } catch (Throwable t) { 136 result.resultCode = RESULT_FAILURE; 137 } 138 break; 139 case PROFILE_PEER_DEVICE: 140 Slog.d(TAG, "Verifying Peer Device profile."); 141 result.resultCode = mPeerDeviceVerifier.verifyAttestation( 142 localBindingType, requirements, attestation); 143 break; 144 default: 145 Slog.d(TAG, "No profile found, defaulting."); 146 result.resultCode = RESULT_UNKNOWN; 147 } 148 resultCallback.complete(result); 149 } 150 151 @Override onStart()152 public void onStart() { 153 Slog.d(TAG, "Started"); 154 publishBinderService(Context.ATTESTATION_VERIFICATION_SERVICE, mService); 155 } 156 157 158 static class DumpLogger { 159 private final ArrayDeque<DumpData> mData = new ArrayDeque<>(DUMP_EVENT_LOG_SIZE); 160 private int mEventsLogged = 0; 161 logAttempt(DumpData data)162 void logAttempt(DumpData data) { 163 synchronized (mData) { 164 if (mData.size() == DUMP_EVENT_LOG_SIZE) { 165 mData.removeFirst(); 166 } 167 168 mEventsLogged++; 169 data.mEventNumber = mEventsLogged; 170 171 data.mEventTimeMs = System.currentTimeMillis(); 172 173 mData.add(data); 174 } 175 } 176 dumpTo(IndentingPrintWriter writer)177 void dumpTo(IndentingPrintWriter writer) { 178 synchronized (mData) { 179 for (DumpData data : mData.reversed()) { 180 writer.println( 181 TextUtils.formatSimple("Verification #%d [%s]", data.mEventNumber, 182 TimeUtils.formatForLogging(data.mEventTimeMs))); 183 writer.increaseIndent(); 184 data.dumpTo(writer); 185 writer.decreaseIndent(); 186 } 187 } 188 } 189 } 190 191 abstract static class DumpData { 192 protected int mEventNumber = -1; 193 protected long mEventTimeMs = -1; 194 dumpTo(IndentingPrintWriter writer)195 abstract void dumpTo(IndentingPrintWriter writer); 196 } 197 } 198