1 /* Copyright 2017 The Android Open Source Project
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions
5  * are met:
6  * 1. Redistributions of source code must retain the above copyright
7  *    notice, this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright
9  *    notice, this list of conditions and the following disclaimer in the
10  *    documentation and/or other materials provided with the distribution.
11  *
12  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
13  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
16  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 
23 #include "keystore_backend_binder.h"
24 
25 #include <android-base/logging.h>
26 #include <android/security/keystore/IKeystoreService.h>
27 #include <binder/IServiceManager.h>
28 #include <binder/ProcessState.h>
29 #include <keystore/KeyCharacteristics.h>
30 #include <keystore/KeymasterArguments.h>
31 #include <keystore/KeymasterBlob.h>
32 #include <keystore/KeystoreResponse.h>
33 #include <keystore/OperationResult.h>
34 #include <keystore/keymaster_types.h>
35 #include <keystore/keystore.h>
36 #include <keystore/keystore_hidl_support.h>
37 #include <keystore/keystore_promises.h>
38 #include <keystore/keystore_return_types.h>
39 
40 #include <future>
41 #include <thread>
42 
43 using android::security::keystore::IKeystoreService;
44 using namespace android;
45 using keystore::hidl_vec;
46 
47 using android::hardware::keymaster::V4_0::Algorithm;
48 using android::hardware::keymaster::V4_0::authorizationValue;
49 using android::hardware::keymaster::V4_0::Digest;
50 using android::hardware::keymaster::V4_0::KeyFormat;
51 using android::hardware::keymaster::V4_0::KeyParameter;
52 using android::hardware::keymaster::V4_0::KeyPurpose;
53 using android::hardware::keymaster::V4_0::NullOr;
54 using android::hardware::keymaster::V4_0::PaddingMode;
55 using android::hardware::keymaster::V4_0::TAG_ALGORITHM;
56 using android::hardware::keymaster::V4_0::TAG_DIGEST;
57 using android::hardware::keymaster::V4_0::TAG_PADDING;
58 using android::security::keymaster::ExportResult;
59 using android::security::keymaster::KeyCharacteristics;
60 using android::security::keymaster::KeymasterArguments;
61 using android::security::keymaster::KeymasterBlob;
62 using android::security::keymaster::OperationResult;
63 
64 using KSReturn = keystore::KeyStoreNativeReturnCode;
65 
66 namespace {
67 const char keystore_service_name[] = "android.security.keystore";
68 constexpr int32_t UID_SELF = -1;
69 
70 using keystore::KeyCharacteristicsPromise;
71 using keystore::KeystoreExportPromise;
72 using keystore::KeystoreResponsePromise;
73 using keystore::OperationResultPromise;
74 
75 }  // namespace
76 
77 #define AT __func__ << ":" << __LINE__ << " "
78 
getKeyAlgoritmFromKeyCharacteristics(const::android::security::keymaster::KeyCharacteristics & characteristics)79 static NullOr<const Algorithm&> getKeyAlgoritmFromKeyCharacteristics(
80     const ::android::security::keymaster::KeyCharacteristics& characteristics) {
81     for (const auto& param : characteristics.hardwareEnforced.getParameters()) {
82         auto algo = authorizationValue(TAG_ALGORITHM, param);
83         if (algo.isOk()) return algo;
84     }
85     for (const auto& param : characteristics.softwareEnforced.getParameters()) {
86         auto algo = authorizationValue(TAG_ALGORITHM, param);
87         if (algo.isOk()) return algo;
88     }
89     return {};
90 }
91 
KeystoreBackendBinder()92 KeystoreBackendBinder::KeystoreBackendBinder() {
93     android::ProcessState::self()->startThreadPool();
94 }
95 
sign(const char * key_id,const uint8_t * in,size_t len,uint8_t ** reply,size_t * reply_len)96 int32_t KeystoreBackendBinder::sign(const char* key_id, const uint8_t* in, size_t len,
97                                     uint8_t** reply, size_t* reply_len) {
98     sp<IServiceManager> sm = defaultServiceManager();
99     sp<IBinder> binder = sm->getService(String16(keystore_service_name));
100     sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
101 
102     if (service == nullptr) {
103         LOG(ERROR) << AT << "could not contact keystore";
104         return -1;
105     }
106 
107     String16 key_name16(key_id);
108     int32_t error_code;
109     android::sp<KeyCharacteristicsPromise> kc_promise(new KeyCharacteristicsPromise);
110     auto kc_future = kc_promise->get_future();
111     auto binder_result = service->getKeyCharacteristics(kc_promise, key_name16, KeymasterBlob(),
112                                                         KeymasterBlob(), UID_SELF, &error_code);
113     if (!binder_result.isOk()) {
114         LOG(ERROR) << AT << "communication error while calling keystore";
115         return -1;
116     }
117     if (!KSReturn(error_code).isOk()) {
118         LOG(ERROR) << AT << "getKeyCharacteristics failed: " << error_code;
119         return -1;
120     }
121 
122     auto [km_response, characteristics] = kc_future.get();
123 
124     if (!KSReturn(km_response.response_code()).isOk()) {
125         LOG(ERROR) << AT << "getKeyCharacteristics failed: " << km_response.response_code();
126         return -1;
127     }
128 
129     auto algorithm = getKeyAlgoritmFromKeyCharacteristics(characteristics);
130     if (!algorithm.isOk()) {
131         LOG(ERROR) << AT << "could not get algorithm from key characteristics";
132         return -1;
133     }
134 
135     hidl_vec<KeyParameter> params(3);
136     params[0] = Authorization(TAG_DIGEST, Digest::NONE);
137     params[1] = Authorization(TAG_PADDING, PaddingMode::NONE);
138     params[2] = Authorization(TAG_ALGORITHM, algorithm.value());
139 
140     android::sp<android::IBinder> token(new android::BBinder);
141     sp<OperationResultPromise> promise(new OperationResultPromise());
142     auto future = promise->get_future();
143     binder_result = service->begin(promise, token, key_name16, (int)KeyPurpose::SIGN,
144                                    true /*pruneable*/, KeymasterArguments(params),
145                                    std::vector<uint8_t>() /* entropy */, UID_SELF, &error_code);
146     if (!binder_result.isOk()) {
147         LOG(ERROR) << AT << "communication error while calling keystore";
148         return -1;
149     }
150 
151     keystore::KeyStoreNativeReturnCode rc(error_code);
152     if (!rc.isOk()) {
153         LOG(ERROR) << AT << "Keystore begin returned: " << error_code;
154         return -1;
155     }
156     OperationResult result = future.get();
157 
158     if (!result.resultCode.isOk()) {
159         LOG(ERROR) << AT << "begin failed: " << result.resultCode;
160         return -1;
161     }
162     auto handle = std::move(result.token);
163 
164     do {
165         future = {};
166         promise = new OperationResultPromise();
167         future = promise->get_future();
168         binder_result = service->update(promise, handle, KeymasterArguments(params),
169                                         std::vector<uint8_t>(in, in + len), &error_code);
170         if (!binder_result.isOk()) {
171             LOG(ERROR) << AT << "communication error while calling keystore";
172             return -1;
173         }
174 
175         rc = keystore::KeyStoreNativeReturnCode(error_code);
176         if (!rc.isOk()) {
177             LOG(ERROR) << AT << "Keystore update returned: " << error_code;
178             return -1;
179         }
180         result = future.get();
181 
182         if (!result.resultCode.isOk()) {
183             LOG(ERROR) << AT << "update failed: " << result.resultCode;
184             return -1;
185         }
186 
187         if (result.inputConsumed > len) {
188             LOG(ERROR) << AT << "update consumed more data than provided";
189             sp<KeystoreResponsePromise> abortPromise(new KeystoreResponsePromise);
190             auto abortFuture = abortPromise->get_future();
191             binder_result = service->abort(abortPromise, handle, &error_code);
192             if (!binder_result.isOk()) {
193                 LOG(ERROR) << AT << "communication error while calling keystore";
194                 return -1;
195             }
196             // This is mainly for logging since we already failed.
197             // But if abort returned OK we have to wait untill abort calls the callback
198             // hence the call to abortFuture.get().
199             if (!KSReturn(error_code).isOk()) {
200                 LOG(ERROR) << AT << "abort failed: " << error_code;
201             } else if (!(rc = KSReturn(abortFuture.get().response_code())).isOk()) {
202                 LOG(ERROR) << AT << "abort failed: " << rc;
203             }
204             return -1;
205         }
206         len -= result.inputConsumed;
207         in += result.inputConsumed;
208     } while (len > 0);
209 
210     future = {};
211     promise = new OperationResultPromise();
212     future = promise->get_future();
213 
214     binder_result = service->finish(
215         promise, handle, KeymasterArguments(params), std::vector<uint8_t>() /* input */,
216         std::vector<uint8_t>() /* signature */, std::vector<uint8_t>() /* entropy */, &error_code);
217 
218     if (!binder_result.isOk()) {
219         LOG(ERROR) << AT << "communication error while calling keystore";
220         return -1;
221     }
222 
223     rc = keystore::KeyStoreNativeReturnCode(error_code);
224     if (!rc.isOk()) {
225         LOG(ERROR) << AT << "Keystore finish returned: " << error_code;
226         return -1;
227     }
228     result = future.get();
229 
230     if (!result.resultCode.isOk()) {
231         LOG(ERROR) << AT << "finish failed: " << result.resultCode;
232         return -1;
233     }
234 
235     hidl_vec<uint8_t> reply_hidl(result.data);
236     if (reply_len) {
237         *reply_len = reply_hidl.size();
238     }
239     if (reply) {
240         *reply = reply_hidl.releaseData();
241     }
242     return 0;
243 }
244 
get_pubkey(const char * key_id,uint8_t ** pubkey,size_t * pubkey_len)245 int32_t KeystoreBackendBinder::get_pubkey(const char* key_id, uint8_t** pubkey,
246                                           size_t* pubkey_len) {
247     sp<IServiceManager> sm = defaultServiceManager();
248     sp<IBinder> binder = sm->getService(String16(keystore_service_name));
249     sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
250 
251     if (service == nullptr) {
252         LOG(ERROR) << AT << "could not contact keystore";
253         return -1;
254     }
255 
256     int32_t error_code;
257     android::sp<KeystoreExportPromise> promise(new KeystoreExportPromise);
258     auto future = promise->get_future();
259     auto binder_result = service->exportKey(
260         promise, String16(key_id), static_cast<int32_t>(KeyFormat::X509),
261         KeymasterBlob() /* clientId */, KeymasterBlob() /* appData */, UID_SELF, &error_code);
262     if (!binder_result.isOk()) {
263         LOG(ERROR) << AT << "communication error while calling keystore";
264         return -1;
265     }
266 
267     KSReturn rc(error_code);
268     if (!rc.isOk()) {
269         LOG(ERROR) << AT << "exportKey failed: " << error_code;
270         return -1;
271     }
272 
273     auto export_result = future.get();
274     if (!export_result.resultCode.isOk()) {
275         LOG(ERROR) << AT << "exportKey failed: " << export_result.resultCode;
276         return -1;
277     }
278 
279     if (pubkey_len) {
280         *pubkey_len = export_result.exportData.size();
281     }
282     if (pubkey) {
283         *pubkey = export_result.exportData.releaseData();
284     }
285     return 0;
286 }
287