blob: 50b78c3d32eab8bb7fb308caa237a7d37df42c49 [file] [log] [blame]
Max Birese24b7822020-12-03 14:49:58 -08001/**
2 * Copyright (C) 2020 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
17package com.android.remoteprovisioner;
18
19import android.app.job.JobParameters;
20import android.app.job.JobService;
Max Bires0dbe39c2021-02-07 18:39:00 -080021import android.hardware.security.keymint.SecurityLevel;
Max Birese24b7822020-12-03 14:49:58 -080022import android.os.RemoteException;
23import android.os.ServiceManager;
24import android.security.remoteprovisioning.AttestationPoolStatus;
25import android.security.remoteprovisioning.IRemoteProvisioning;
26import android.util.Log;
27
Max Birese24b7822020-12-03 14:49:58 -080028/**
29 * A class that extends JobService in order to be scheduled to check the status of the attestation
30 * key pool at regular intervals. If the job determines that more keys need to be generated and
31 * signed, it drives that process.
32 */
33public class PeriodicProvisioner extends JobService {
34 //TODO(b/176249146): Replace default key amount with a value fetched from the server.
35 private static final int TOTAL_SIGNED_KEYS = 10;
36
37 private static final String SERVICE = "android.security.remoteprovisioning";
38 private static final String TAG = "RemoteProvisioningService";
Max Biresfeff69a2021-02-08 21:28:37 -080039 private ProvisionerThread mProvisionerThread;
Max Birese24b7822020-12-03 14:49:58 -080040
Max Biresfeff69a2021-02-08 21:28:37 -080041 /**
42 * Starts the periodic provisioning job, which will occasionally check the attestation key pool
43 * and provision it as necessary.
44 */
Max Birese24b7822020-12-03 14:49:58 -080045 public boolean onStartJob(JobParameters params) {
46 Log.d(TAG, "Starting provisioning job");
Max Biresfeff69a2021-02-08 21:28:37 -080047 mProvisionerThread = new ProvisionerThread(params);
48 mProvisionerThread.start();
Max Birese24b7822020-12-03 14:49:58 -080049 return true;
50 }
51
Max Biresfeff69a2021-02-08 21:28:37 -080052 /**
53 * Allows the job to be stopped if need be.
54 */
Max Birese24b7822020-12-03 14:49:58 -080055 public boolean onStopJob(JobParameters params) {
Max Biresfeff69a2021-02-08 21:28:37 -080056 mProvisionerThread.stop();
Max Birese24b7822020-12-03 14:49:58 -080057 return false;
58 }
59
60 private class ProvisionerThread extends Thread {
61 private JobParameters mParams;
62
Max Biresfeff69a2021-02-08 21:28:37 -080063 ProvisionerThread(JobParameters params) {
Max Birese24b7822020-12-03 14:49:58 -080064 mParams = params;
65 }
66
67 public void run() {
68 try {
69 IRemoteProvisioning binder =
Max Biresfeff69a2021-02-08 21:28:37 -080070 IRemoteProvisioning.Stub.asInterface(ServiceManager.getService(SERVICE));
Max Birese24b7822020-12-03 14:49:58 -080071 // TODO: Replace expiration date parameter with value fetched from server
Max Bires0dbe39c2021-02-07 18:39:00 -080072 checkAndProvision(binder, 1, SecurityLevel.TRUSTED_ENVIRONMENT);
Max Birese24b7822020-12-03 14:49:58 -080073 jobFinished(mParams, false /* wantsReschedule */);
74 } catch (RemoteException e) {
75 jobFinished(mParams, true /* wantsReschedule */);
Max Bires0dbe39c2021-02-07 18:39:00 -080076 Log.e(TAG, "Error on the binder side during provisioning.", e);
Max Birese24b7822020-12-03 14:49:58 -080077 } catch (InterruptedException e) {
78 jobFinished(mParams, true /* wantsReschedule */);
79 Log.e(TAG, "Provisioner thread interrupted.", e);
80 }
81 }
Max Bires0dbe39c2021-02-07 18:39:00 -080082
83 private void checkAndProvision(IRemoteProvisioning binder, long expiringBy, int secLevel)
84 throws InterruptedException, RemoteException {
Max Biresfeff69a2021-02-08 21:28:37 -080085 AttestationPoolStatus pool = binder.getPoolStatus(expiringBy, secLevel);
Max Bires0dbe39c2021-02-07 18:39:00 -080086 int generated = 0;
87 while (generated + pool.total - pool.expiring < TOTAL_SIGNED_KEYS) {
88 generated++;
89 binder.generateKeyPair(false /* isTestMode */, secLevel);
90 Thread.sleep(5000);
91 }
92 if (generated > 0) {
93 Log.d(TAG, "Keys generated, moving to provisioning process.");
94 Provisioner.provisionCerts(generated, secLevel, binder);
95 }
96 }
Max Birese24b7822020-12-03 14:49:58 -080097 }
98}