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