1 /*
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
17 #include "apc_compat.hpp"
18 #include <android-base/logging.h>
19 #include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
20 #include <hwbinder/IBinder.h>
21
22 #include <memory>
23 #include <string>
24 #include <thread>
25 #include <vector>
26
27 #define LOG_TAG "keystore2_apc_compat"
28
29 namespace keystore2 {
30
31 using android::sp;
32 using android::hardware::hidl_death_recipient;
33 using android::hardware::hidl_vec;
34 using android::hardware::Return;
35 using android::hardware::Status;
36 using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
37 using android::hardware::confirmationui::V1_0::IConfirmationUI;
38 using android::hardware::confirmationui::V1_0::ResponseCode;
39 using android::hardware::confirmationui::V1_0::UIOption;
40
responseCode2Compat(ResponseCode rc)41 static uint32_t responseCode2Compat(ResponseCode rc) {
42 switch (rc) {
43 case ResponseCode::OK:
44 return APC_COMPAT_ERROR_OK;
45 case ResponseCode::Canceled:
46 return APC_COMPAT_ERROR_CANCELLED;
47 case ResponseCode::Aborted:
48 return APC_COMPAT_ERROR_ABORTED;
49 case ResponseCode::OperationPending:
50 return APC_COMPAT_ERROR_OPERATION_PENDING;
51 case ResponseCode::Ignored:
52 return APC_COMPAT_ERROR_IGNORED;
53 case ResponseCode::SystemError:
54 case ResponseCode::Unimplemented:
55 case ResponseCode::Unexpected:
56 case ResponseCode::UIError:
57 case ResponseCode::UIErrorMissingGlyph:
58 case ResponseCode::UIErrorMessageTooLong:
59 case ResponseCode::UIErrorMalformedUTF8Encoding:
60 default:
61 return APC_COMPAT_ERROR_SYSTEM_ERROR;
62 }
63 }
64
65 class ConfuiCompatSession : public IConfirmationResultCallback, public hidl_death_recipient {
66 public:
tryGetService()67 static sp<ConfuiCompatSession>* tryGetService() {
68 sp<IConfirmationUI> service = IConfirmationUI::tryGetService();
69 if (service) {
70 return new sp(new ConfuiCompatSession(std::move(service)));
71 } else {
72 return nullptr;
73 }
74 }
75
promptUserConfirmation(ApcCompatCallback callback,const char * prompt_text,const uint8_t * extra_data,size_t extra_data_size,const char * locale,ApcCompatUiOptions ui_options)76 uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
77 const uint8_t* extra_data, size_t extra_data_size,
78 const char* locale, ApcCompatUiOptions ui_options) {
79 std::string hidl_prompt(prompt_text);
80 std::vector<uint8_t> hidl_extra(extra_data, extra_data + extra_data_size);
81 std::string hidl_locale(locale);
82 std::vector<UIOption> hidl_ui_options;
83 if (ui_options.inverted) {
84 hidl_ui_options.push_back(UIOption::AccessibilityInverted);
85 }
86 if (ui_options.magnified) {
87 hidl_ui_options.push_back(UIOption::AccessibilityMagnified);
88 }
89 auto lock = std::lock_guard(callback_lock_);
90 if (callback_.result != nullptr) {
91 return APC_COMPAT_ERROR_OPERATION_PENDING;
92 }
93 auto err = service_->linkToDeath(sp(this), 0);
94 if (!err.isOk()) {
95 LOG(ERROR) << "Communication error: promptUserConfirmation: "
96 "Trying to register death recipient: "
97 << err.description();
98 return APC_COMPAT_ERROR_SYSTEM_ERROR;
99 }
100
101 auto rc = service_->promptUserConfirmation(sp(this), hidl_prompt, hidl_extra, hidl_locale,
102 hidl_ui_options);
103 if (!rc.isOk()) {
104 LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.description();
105 }
106 if (rc == ResponseCode::OK) {
107 callback_ = callback;
108 }
109 return responseCode2Compat(rc.withDefault(ResponseCode::SystemError));
110 }
111
abort()112 void abort() { service_->abort(); }
113
114 void
finalize(ResponseCode responseCode,std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> dataConfirmed,std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> confirmationToken)115 finalize(ResponseCode responseCode,
116 std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> dataConfirmed,
117 std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> confirmationToken) {
118 ApcCompatCallback callback;
119 {
120 auto lock = std::lock_guard(callback_lock_);
121 // Calling the callback consumes the callback data structure. We have to make
122 // sure that it can only be called once.
123 callback = callback_;
124 callback_ = {nullptr, nullptr};
125 // Unlock the callback_lock_ here. It must never be held while calling the callback.
126 }
127
128 if (callback.result != nullptr) {
129 service_->unlinkToDeath(sp(this));
130
131 size_t dataConfirmedSize = 0;
132 const uint8_t* dataConfirmedPtr = nullptr;
133 size_t confirmationTokenSize = 0;
134 const uint8_t* confirmationTokenPtr = nullptr;
135 if (responseCode == ResponseCode::OK) {
136 if (dataConfirmed) {
137 dataConfirmedPtr = dataConfirmed->get().data();
138 dataConfirmedSize = dataConfirmed->get().size();
139 }
140 if (dataConfirmed) {
141 confirmationTokenPtr = confirmationToken->get().data();
142 confirmationTokenSize = confirmationToken->get().size();
143 }
144 }
145 callback.result(callback.data, responseCode2Compat(responseCode), dataConfirmedPtr,
146 dataConfirmedSize, confirmationTokenPtr, confirmationTokenSize);
147 }
148 }
149
150 // IConfirmationResultCallback overrides:
result(ResponseCode responseCode,const hidl_vec<uint8_t> & dataConfirmed,const hidl_vec<uint8_t> & confirmationToken)151 android::hardware::Return<void> result(ResponseCode responseCode,
152 const hidl_vec<uint8_t>& dataConfirmed,
153 const hidl_vec<uint8_t>& confirmationToken) override {
154 finalize(responseCode, dataConfirmed, confirmationToken);
155 return Status::ok();
156 };
157
serviceDied(uint64_t,const::android::wp<::android::hidl::base::V1_0::IBase> &)158 void serviceDied(uint64_t /* cookie */,
159 const ::android::wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
160 finalize(ResponseCode::SystemError, {}, {});
161 }
162
163 private:
ConfuiCompatSession(sp<IConfirmationUI> service)164 ConfuiCompatSession(sp<IConfirmationUI> service)
165 : service_(service), callback_{nullptr, nullptr} {}
166 sp<IConfirmationUI> service_;
167
168 // The callback_lock_ protects the callback_ field against concurrent modification.
169 // IMPORTANT: It must never be held while calling the call back.
170 std::mutex callback_lock_;
171 ApcCompatCallback callback_;
172 };
173
174 } // namespace keystore2
175
176 using namespace keystore2;
177
tryGetUserConfirmationService()178 ApcCompatServiceHandle tryGetUserConfirmationService() {
179 return reinterpret_cast<ApcCompatServiceHandle>(ConfuiCompatSession::tryGetService());
180 }
181
promptUserConfirmation(ApcCompatServiceHandle handle,ApcCompatCallback callback,const char * prompt_text,const uint8_t * extra_data,size_t extra_data_size,char const * locale,ApcCompatUiOptions ui_options)182 uint32_t promptUserConfirmation(ApcCompatServiceHandle handle, ApcCompatCallback callback,
183 const char* prompt_text, const uint8_t* extra_data,
184 size_t extra_data_size, char const* locale,
185 ApcCompatUiOptions ui_options) {
186 auto session = reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
187 return (*session)->promptUserConfirmation(callback, prompt_text, extra_data, extra_data_size,
188 locale, ui_options);
189 }
190
abortUserConfirmation(ApcCompatServiceHandle handle)191 void abortUserConfirmation(ApcCompatServiceHandle handle) {
192 auto session = reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
193 (*session)->abort();
194 }
195
closeUserConfirmationService(ApcCompatServiceHandle handle)196 void closeUserConfirmationService(ApcCompatServiceHandle handle) {
197 // Closing the handle implicitly aborts an ongoing sessions.
198 // Note that a resulting callback is still safely conducted, because we only delete a
199 // StrongPointer below. libhwbinder still owns another StrongPointer to this session.
200 abortUserConfirmation(handle);
201 delete reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
202 }
203
204 const ApcCompatServiceHandle INVALID_SERVICE_HANDLE = nullptr;
205