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