1 #include "include/wifikeystorehal/keystore.h"
2
3 #include <aidl/android/security/legacykeystore/ILegacyKeystore.h>
4 #include <aidl/android/system/keystore2/IKeystoreService.h>
5 #include <aidl/android/system/keystore2/ResponseCode.h>
6 #include <android-base/logging.h>
7 #include <android-base/strings.h>
8 #include <android/binder_manager.h>
9 #include <binder/IServiceManager.h>
10 #include <openssl/base.h>
11 #include <openssl/bio.h>
12 #include <openssl/pem.h>
13 #include <openssl/x509.h>
14 #include <private/android_filesystem_config.h>
15 #include <stdio.h>
16
17 #include <vector>
18
19 #include "wifikeystorehal_utils.h"
20
21 #define AT __func__ << ":" << __LINE__ << " "
22
23 namespace ks2 = ::aidl::android::system::keystore2;
24 namespace lks = ::aidl::android::security::legacykeystore;
25 namespace KMV1 = ::aidl::android::hardware::security::keymint;
26
27 namespace {
28
29 constexpr const int64_t KS2_NAMESPACE_WIFI = 102;
30
31 constexpr const char kKeystore2ServiceName[] = "android.system.keystore2.IKeystoreService/default";
32 constexpr const char kLegacyKeystoreServiceName[] = "android.security.legacykeystore";
33
34 const std::string keystore2_grant_id_prefix("ks2_keystore-engine_grant_id:");
35
mkKeyDescriptor(const std::string & alias)36 ks2::KeyDescriptor mkKeyDescriptor(const std::string& alias) {
37 // If the key_id starts with the grant id prefix, we parse the following string as numeric
38 // grant id. We can then use the grant domain without alias to load the designated key.
39 if (android::base::StartsWith(alias, keystore2_grant_id_prefix)) {
40 std::stringstream s(alias.substr(keystore2_grant_id_prefix.size()));
41 uint64_t tmp;
42 s >> std::hex >> tmp;
43 if (s.fail() || !s.eof()) {
44 LOG(ERROR) << AT << "Couldn't parse grant name: " << alias;
45 }
46 return {
47 .domain = ks2::Domain::GRANT,
48 .nspace = static_cast<int64_t>(tmp),
49 .alias = std::nullopt,
50 .blob = std::nullopt,
51 };
52 } else {
53 return {
54 .domain = ks2::Domain::SELINUX,
55 .nspace = KS2_NAMESPACE_WIFI,
56 .alias = alias,
57 .blob = std::nullopt,
58 };
59 }
60 }
61
62 using android::hardware::hidl_string;
63 using android::hardware::hidl_vec;
64
65 // Helper method to convert certs in DER format to PEM format required by
66 // openssl library used by supplicant. If boringssl cannot parse the input as one or more
67 // X509 certificates in DER encoding, this function returns the input as-is. The assumption in
68 // that case is that either the `cert_bytes` is already PEM encoded, or `cert_bytes` is something
69 // completely different that was intentionally installed by the Wi-Fi subsystem and it must not
70 // be changed here.
71 // If any error occurs during PEM encoding, this function returns std::nullopt and logs an error.
convertDerCertToPemOrPassthrough(const std::vector<uint8_t> & cert_bytes)72 std::optional<hidl_vec<uint8_t>> convertDerCertToPemOrPassthrough(
73 const std::vector<uint8_t>& cert_bytes) {
74 // If cert_bytes is a DER encoded X509 certificate, it must be reencoded as PEM, because
75 // wpa_supplicant only understand PEM. Otherwise the cert_bytes are returned as is.
76 const uint8_t* cert_current = cert_bytes.data();
77 const uint8_t* cert_end = cert_current + cert_bytes.size();
78 bssl::UniquePtr<BIO> pem_bio(BIO_new(BIO_s_mem()));
79 while (cert_current < cert_end) {
80 auto cert =
81 bssl::UniquePtr<X509>(d2i_X509(nullptr, &cert_current, cert_end - cert_current));
82 // If part of the bytes cannot be parsed as X509 DER certificate, the original blob
83 // shall be returned as-is.
84 if (!cert) {
85 LOG(WARNING) << AT
86 << "Could not parse DER X509 cert from buffer. Returning blob as is.";
87 return cert_bytes;
88 }
89
90 if (!PEM_write_bio_X509(pem_bio.get(), cert.get())) {
91 LOG(ERROR) << AT << "Could not convert cert to PEM format.";
92 return std::nullopt;
93 }
94 }
95
96 const uint8_t* pem_bytes;
97 size_t pem_len;
98 if (!BIO_mem_contents(pem_bio.get(), &pem_bytes, &pem_len)) {
99 LOG(ERROR) << AT << "Could not extract pem_bytes from BIO.";
100 return std::nullopt;
101 }
102 return {{pem_bytes, pem_bytes + pem_len}};
103 }
104
keyStore2GetCert(const hidl_string & key)105 std::optional<std::vector<uint8_t>> keyStore2GetCert(const hidl_string& key) {
106 ::ndk::SpAIBinder keystoreBinder(AServiceManager_checkService(kKeystore2ServiceName));
107 auto keystore2 = ks2::IKeystoreService::fromBinder(keystoreBinder);
108
109 if (!keystore2) {
110 LOG(WARNING) << AT << "Unable to connect to Keystore 2.0.";
111 return {};
112 }
113
114 bool ca_cert = false;
115 std::string alias = key.c_str();
116 if (android::base::StartsWith(alias, "CACERT_")) {
117 alias = alias.substr(7);
118 ca_cert = true;
119 } else if (android::base::StartsWith(alias, "USRCERT_")) {
120 alias = alias.substr(8);
121 }
122
123 ks2::KeyDescriptor descriptor = mkKeyDescriptor(alias);
124
125 // If the key_id starts with the grant id prefix, we parse the following string as numeric
126 // grant id. We can then use the grant domain without alias to load the designated key.
127 if (android::base::StartsWith(alias, keystore2_grant_id_prefix)) {
128 std::stringstream s(alias.substr(keystore2_grant_id_prefix.size()));
129 uint64_t tmp;
130 s >> std::hex >> tmp;
131 if (s.fail() || !s.eof()) {
132 LOG(ERROR) << AT << "Couldn't parse grant name: " << alias;
133 }
134 descriptor.nspace = static_cast<int64_t>(tmp);
135 descriptor.domain = ks2::Domain::GRANT;
136 descriptor.alias = std::nullopt;
137 }
138
139 ks2::KeyEntryResponse response;
140 auto rc = keystore2->getKeyEntry(descriptor, &response);
141 if (!rc.isOk()) {
142 if (rc.getServiceSpecificError() != int32_t(ks2::ResponseCode::KEY_NOT_FOUND)) {
143 LOG(WARNING) << AT
144 << "Entry not found in Keystore 2.0. Falling back to legacy keystore.";
145 } else {
146 LOG(ERROR) << AT << "Keystore 2.0 getKeyEntry failed error: " << rc.getDescription();
147 }
148 return {};
149 }
150
151 if (ca_cert && response.metadata.certificateChain) {
152 return std::move(*response.metadata.certificateChain);
153 } else if (!ca_cert && response.metadata.certificate) {
154 return std::move(*response.metadata.certificate);
155 } else {
156 LOG(WARNING) << AT << "No " << (ca_cert ? "CA" : "client") << " certificate found. "
157 << "Falling back to legacy keystore.";
158 return {};
159 }
160 }
161
keyStore2GetPubKey(const hidl_string & key)162 std::optional<std::vector<uint8_t>> keyStore2GetPubKey(const hidl_string& key) {
163 ::ndk::SpAIBinder keystoreBinder(AServiceManager_checkService(kKeystore2ServiceName));
164 auto keystore2 = ks2::IKeystoreService::fromBinder(keystoreBinder);
165
166 if (!keystore2) {
167 LOG(WARNING) << AT << "Unable to connect to Keystore 2.0.";
168 return std::nullopt;
169 }
170
171 std::string alias = key.c_str();
172 if (android::base::StartsWith(alias, "USRPKEY_")) {
173 alias = alias.substr(8);
174 }
175
176 ks2::KeyDescriptor descriptor = mkKeyDescriptor(alias);
177
178 ks2::KeyEntryResponse response;
179 auto rc = keystore2->getKeyEntry(descriptor, &response);
180 if (!rc.isOk()) {
181 auto exception_code = rc.getExceptionCode();
182 if (exception_code == EX_SERVICE_SPECIFIC) {
183 LOG(ERROR) << AT << "Keystore getKeyEntry returned service specific error: "
184 << rc.getServiceSpecificError();
185 } else {
186 LOG(ERROR) << AT << "Communication with Keystore getKeyEntry failed error: "
187 << exception_code;
188 }
189 return std::nullopt;
190 }
191
192 if (!response.metadata.certificate) {
193 LOG(ERROR) << AT << "No public key found.";
194 return std::nullopt;
195 }
196
197 std::optional<std::vector<uint8_t>> pub_key(extractPubKey(*response.metadata.certificate));
198 return pub_key;
199 }
200
keyStore2Sign(const hidl_string & key,const hidl_vec<uint8_t> & dataToSign)201 std::optional<std::vector<uint8_t>> keyStore2Sign(const hidl_string& key,
202 const hidl_vec<uint8_t>& dataToSign) {
203 ::ndk::SpAIBinder keystoreBinder(AServiceManager_checkService(kKeystore2ServiceName));
204 auto keystore2 = ks2::IKeystoreService::fromBinder(keystoreBinder);
205
206 if (!keystore2) {
207 LOG(WARNING) << AT << "Unable to connect to Keystore 2.0.";
208 return std::nullopt;
209 }
210
211 std::string alias = key.c_str();
212 if (android::base::StartsWith(alias, "USRPKEY_")) {
213 alias = alias.substr(8);
214 }
215
216 ks2::KeyDescriptor descriptor = mkKeyDescriptor(alias);
217
218 ks2::KeyEntryResponse response;
219 auto rc = keystore2->getKeyEntry(descriptor, &response);
220 if (!rc.isOk()) {
221 auto exception_code = rc.getExceptionCode();
222 if (exception_code == EX_SERVICE_SPECIFIC) {
223 LOG(ERROR) << AT << "Keystore getKeyEntry returned service specific error: "
224 << rc.getServiceSpecificError();
225 } else {
226 LOG(ERROR) << AT << "Communication with Keystore getKeyEntry failed error: "
227 << exception_code;
228 }
229 return std::nullopt;
230 }
231
232 std::optional<KMV1::Algorithm> algorithm;
233 for (auto& element : response.metadata.authorizations) {
234 if (element.keyParameter.tag == KMV1::Tag::ALGORITHM) {
235 algorithm = element.keyParameter.value.get<KMV1::KeyParameterValue::algorithm>();
236 }
237 }
238
239 if (!algorithm) {
240 LOG(ERROR) << AT << "Could not find signing algorithm.";
241 return std::nullopt;
242 }
243
244 auto sec_level = response.iSecurityLevel;
245
246 std::vector<KMV1::KeyParameter> op_params(4);
247 op_params[0] = KMV1::KeyParameter{
248 .tag = KMV1::Tag::PURPOSE,
249 .value = KMV1::KeyParameterValue::make<KMV1::KeyParameterValue::keyPurpose>(
250 KMV1::KeyPurpose::SIGN)};
251 op_params[1] = KMV1::KeyParameter{
252 .tag = KMV1::Tag::ALGORITHM,
253 .value = KMV1::KeyParameterValue::make<KMV1::KeyParameterValue::algorithm>(*algorithm)};
254 op_params[2] = KMV1::KeyParameter{
255 .tag = KMV1::Tag::PADDING,
256 .value = KMV1::KeyParameterValue::make<KMV1::KeyParameterValue::paddingMode>(
257 KMV1::PaddingMode::NONE)};
258 op_params[3] = KMV1::KeyParameter{
259 .tag = KMV1::Tag::DIGEST,
260 .value =
261 KMV1::KeyParameterValue::make<KMV1::KeyParameterValue::digest>(KMV1::Digest::NONE)};
262
263 ks2::CreateOperationResponse op_response;
264
265 rc = sec_level->createOperation(descriptor, op_params, false /* forced */, &op_response);
266 if (!rc.isOk()) {
267 auto exception_code = rc.getExceptionCode();
268 if (exception_code == EX_SERVICE_SPECIFIC) {
269 LOG(ERROR) << AT << "Keystore createOperation returned service specific error: "
270 << rc.getServiceSpecificError();
271 } else {
272 LOG(ERROR) << AT << "Communication with Keystore createOperation failed error: "
273 << exception_code;
274 }
275 return std::nullopt;
276 }
277
278 auto op = op_response.iOperation;
279 std::optional<std::vector<uint8_t>> output = std::nullopt;
280
281 rc = op->finish(dataToSign, {}, &output);
282 if (!rc.isOk()) {
283 auto exception_code = rc.getExceptionCode();
284 if (exception_code == EX_SERVICE_SPECIFIC) {
285 LOG(ERROR) << AT << "Keystore finish returned service specific error: "
286 << rc.getServiceSpecificError();
287 } else {
288 LOG(ERROR) << AT
289 << "Communication with Keystore finish failed error: " << exception_code;
290 }
291 return std::nullopt;
292 }
293
294 if (!output) {
295 LOG(ERROR) << AT << "Could not get a signature from Keystore.";
296 }
297
298 return output;
299 }
300
getLegacyKeystoreBlob(const hidl_string & key)301 std::optional<std::vector<uint8_t>> getLegacyKeystoreBlob(const hidl_string& key) {
302 ::ndk::SpAIBinder keystoreBinder(AServiceManager_checkService(kLegacyKeystoreServiceName));
303 auto legacyKeystore = lks::ILegacyKeystore::fromBinder(keystoreBinder);
304
305 if (!legacyKeystore) {
306 LOG(WARNING) << AT << "Unable to connect to LegacyKeystore";
307 return std::nullopt;
308 }
309
310 std::optional<std::vector<uint8_t>> blob(std::vector<uint8_t>{});
311 auto rc = legacyKeystore->get(key, AID_WIFI, &*blob);
312 if (!rc.isOk()) {
313 LOG(ERROR) << AT << "Failed to get legacy keystore entry for alias \"" << key
314 << "\": " << rc.getDescription();
315 return std::nullopt;
316 }
317 return blob;
318 }
319
320 }; // namespace
321
322 namespace android {
323 namespace system {
324 namespace wifi {
325 namespace keystore {
326 namespace V1_0 {
327 namespace implementation {
328 // Methods from ::android::hardware::wifi::keystore::V1_0::IKeystore follow.
getBlob(const hidl_string & key,getBlob_cb _hidl_cb)329 Return<void> Keystore::getBlob(const hidl_string& key, getBlob_cb _hidl_cb) {
330 std::vector<uint8_t> result_cert;
331 if (auto ks2_cert = keyStore2GetCert(key)) {
332 result_cert = std::move(*ks2_cert);
333 } else if (auto blob = getLegacyKeystoreBlob(key)) {
334 result_cert = std::move(*blob);
335 } else {
336 LOG(ERROR) << AT << "Failed to get certificate.";
337 _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
338 return Void();
339 }
340
341 if (auto result_cert_hidl = convertDerCertToPemOrPassthrough(result_cert)) {
342 _hidl_cb(KeystoreStatusCode::SUCCESS, *result_cert_hidl);
343 } else {
344 LOG(ERROR) << AT << "Conversion to PEM failed.";
345 _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
346 }
347 return Void();
348 }
349
getPublicKey(const hidl_string & keyId,getPublicKey_cb _hidl_cb)350 Return<void> Keystore::getPublicKey(const hidl_string& keyId, getPublicKey_cb _hidl_cb) {
351 if (auto ks2_pubkey = keyStore2GetPubKey(keyId)) {
352 _hidl_cb(KeystoreStatusCode::SUCCESS, std::move(*ks2_pubkey));
353 } else {
354 LOG(ERROR) << AT << "Failed to get public key.";
355 _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
356 }
357 return Void();
358 }
359
sign(const hidl_string & keyId,const hidl_vec<uint8_t> & dataToSign,sign_cb _hidl_cb)360 Return<void> Keystore::sign(const hidl_string& keyId, const hidl_vec<uint8_t>& dataToSign,
361 sign_cb _hidl_cb) {
362 if (auto ks2_result = keyStore2Sign(keyId, dataToSign)) {
363 _hidl_cb(KeystoreStatusCode::SUCCESS, std::move(*ks2_result));
364 } else {
365 LOG(ERROR) << AT << "Failed to sign.";
366 _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
367 }
368 return Void();
369 }
370
HIDL_FETCH_IKeystore(const char *)371 IKeystore* HIDL_FETCH_IKeystore(const char* /* name */) {
372 return new Keystore();
373 }
374 } // namespace implementation
375 } // namespace V1_0
376 } // namespace keystore
377 } // namespace wifi
378 } // namespace system
379 } // namespace android
380