1 /*
2  * Copyright (C) 2022 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.uwb.secure.provisioning;
18 
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.util.Log;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.server.uwb.secure.SecureElementChannel;
26 import com.android.server.uwb.secure.csml.DeleteAdfCommand;
27 import com.android.server.uwb.secure.csml.DeleteAdfResponse;
28 import com.android.server.uwb.util.ObjectIdentifier;
29 
30 import java.io.IOException;
31 import java.util.UUID;
32 
33 /** Manages the ADF provisioning and deleting. */
34 public class ProvisioningManager {
35     private static final String LOG_TAG = "ProvisioningManager";
36 
37     @NonNull
38     private final SecureElementChannel mSecureElementChannel;
39     @NonNull
40     private Handler mWorkHandler;
41 
42     /** Constructors of {@link ProvisioningManager} */
ProvisioningManager(@onNull SecureElementChannel secureElementChannel, @NonNull Looper workLooper)43     public ProvisioningManager(@NonNull SecureElementChannel secureElementChannel,
44             @NonNull Looper workLooper) {
45 
46         this.mSecureElementChannel = secureElementChannel;
47         this.mWorkHandler = new Handler(workLooper);
48     }
49 
50     /** Provisions the ADF with the signed script file which is encoded as PKCS#7 CMS. */
provisioningAdf(@onNull UUID serviceInstanceId, @NonNull byte[] scriptData, @NonNull ProvisioningCallback provisioningCallback)51     public void provisioningAdf(@NonNull UUID serviceInstanceId, @NonNull byte[] scriptData,
52             @NonNull ProvisioningCallback provisioningCallback) {
53         mWorkHandler.post(() -> {
54             try {
55                 ScriptParser.ScriptContent scriptContent =
56                         ScriptParser.parseSignedScript(scriptData);
57                 ScriptRunner engine = new ScriptRunner(mSecureElementChannel);
58                 engine.run(scriptContent, serviceInstanceId, provisioningCallback);
59             } catch (ProvisioningException e) {
60                 provisioningCallback.onFail(serviceInstanceId);
61             }
62         });
63     }
64 
65     /** Deletes the specified ADF in applet. */
deleteAdf(@onNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid, @NonNull DeleteAdfCallback deleteAdfCallback)66     public void deleteAdf(@NonNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid,
67             @NonNull DeleteAdfCallback deleteAdfCallback) {
68         mWorkHandler.post(() -> {
69             DeleteAdfCommand deleteAdfCommand = DeleteAdfCommand.build(adfOid);
70             try {
71                 if (!mSecureElementChannel.openChannel()) {
72                     throw new IllegalStateException("cannot open se channel.");
73                 }
74                 DeleteAdfResponse response = DeleteAdfResponse.fromResponseApdu(
75                         mSecureElementChannel.transmit(deleteAdfCommand));
76 
77                 if (!response.isSuccess()) {
78                     throw new IllegalStateException("error from applet: " + response.statusWord);
79                 }
80 
81                 deleteAdfCallback.onSuccess(serviceInstanceId, adfOid);
82             } catch (IOException | IllegalStateException e) {
83                 logw("DeleteAdf: error - " + e);
84                 deleteAdfCallback.onFail(serviceInstanceId, adfOid);
85             }
86         });
87     }
88 
89     /** The callback about the result of the provisioning script. */
90     public interface ProvisioningCallback {
91 
92         /** ADF was created in applet. */
onAdfCreated(@onNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid)93         void onAdfCreated(@NonNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid);
94 
95         /** ADF was provisioned in applet. */
onAdfProvisioned(@onNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid)96         void onAdfProvisioned(@NonNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid);
97 
98         /** ADF was created and provisioned, the content should be serialized out of the applet. */
onAdfImported(@onNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid, @NonNull byte[] secureBlob)99         void onAdfImported(@NonNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid,
100                 @NonNull byte[] secureBlob);
101 
102         /** ADF in applet was deleted. */
onAdfDeleted(@onNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid)103         void onAdfDeleted(@NonNull UUID serviceInstanceId, @NonNull ObjectIdentifier adfOid);
104 
105         /** The script was not executed successfully. */
onFail(@onNull UUID serviceInstanceId)106         void onFail(@NonNull UUID serviceInstanceId);
107     }
108 
109     /** Callback for the deleting ADF operation. */
110     public interface DeleteAdfCallback {
111         /** The specified ADF was deleted. */
onSuccess(UUID serviceInstanceId, ObjectIdentifier adfOid)112         void onSuccess(UUID serviceInstanceId, ObjectIdentifier adfOid);
113 
114         /** The specified ADF wasn't deleted. */
onFail(UUID serviceInstanceId, ObjectIdentifier adfOid)115         void onFail(UUID serviceInstanceId, ObjectIdentifier adfOid);
116     }
117 
logw(String debugMsg)118     private void logw(String debugMsg) {
119         Log.w(LOG_TAG, debugMsg);
120     }
121 }
122