blob: bfc68bf08ce038c5a508d2ee12558f752d9697fa [file] [log] [blame]
David Zeuthenab3e5652019-10-28 13:32:48 -04001/*
2 * Copyright (c) 2019, 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#define LOG_TAG "Credential"
18
19#include <android-base/logging.h>
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000020#include <android/binder_manager.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040021#include <android/hardware/identity/support/IdentityCredentialSupport.h>
22
23#include <android/security/identity/ICredentialStore.h>
24
David Zeuthen59102f32020-05-08 10:58:09 -040025#include <android/security/keystore/BnCredstoreTokenCallback.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040026#include <android/security/keystore/IKeystoreService.h>
27#include <binder/IPCThreadState.h>
28#include <binder/IServiceManager.h>
29#include <keymasterV4_0/keymaster_utils.h>
30
31#include <cppbor.h>
32#include <cppbor_parse.h>
David Zeuthen59102f32020-05-08 10:58:09 -040033#include <future>
34#include <tuple>
David Zeuthenab3e5652019-10-28 13:32:48 -040035
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000036#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
37#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
38#include <aidl/android/security/authorization/AuthorizationTokens.h>
39#include <aidl/android/security/authorization/IKeystoreAuthorization.h>
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000040
David Zeuthenab3e5652019-10-28 13:32:48 -040041#include "Credential.h"
42#include "CredentialData.h"
43#include "Util.h"
David Zeuthen472e6c82020-10-16 11:50:13 -040044#include "WritableCredential.h"
David Zeuthenab3e5652019-10-28 13:32:48 -040045
46namespace android {
47namespace security {
48namespace identity {
49
50using std::optional;
David Zeuthen59102f32020-05-08 10:58:09 -040051using std::promise;
52using std::tuple;
David Zeuthenab3e5652019-10-28 13:32:48 -040053
54using android::security::keystore::IKeystoreService;
55
David Zeuthen472e6c82020-10-16 11:50:13 -040056using ::android::hardware::identity::IWritableIdentityCredential;
57
David Zeuthenab3e5652019-10-28 13:32:48 -040058using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
59using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
60using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
61using ::android::hardware::identity::support::sha256;
62
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000063using android::hardware::keymaster::SecurityLevel;
David Zeuthenab3e5652019-10-28 13:32:48 -040064using android::hardware::keymaster::V4_0::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040065using android::hardware::keymaster::V4_0::VerificationToken;
David Zeuthena6f9fba2020-02-11 22:08:27 -050066using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040067using AidlVerificationToken = android::hardware::keymaster::VerificationToken;
David Zeuthenab3e5652019-10-28 13:32:48 -040068
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000069using KeyMintAuthToken = ::aidl::android::hardware::security::keymint::HardwareAuthToken;
70using ::aidl::android::hardware::security::secureclock::TimeStampToken;
71using ::aidl::android::security::authorization::AuthorizationTokens;
72using ::aidl::android::security::authorization::IKeystoreAuthorization;
73
David Zeuthena6f9fba2020-02-11 22:08:27 -050074Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
David Zeuthen472e6c82020-10-16 11:50:13 -040075 const std::string& credentialName, uid_t callingUid,
76 HardwareInformation hwInfo, sp<IIdentityCredentialStore> halStoreBinder,
77 int halApiVersion)
78 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName),
79 callingUid_(callingUid), hwInfo_(std::move(hwInfo)), halStoreBinder_(halStoreBinder),
80 halApiVersion_(halApiVersion) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040081
82Credential::~Credential() {}
83
David Zeuthen472e6c82020-10-16 11:50:13 -040084Status Credential::ensureOrReplaceHalBinder() {
85 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
David Zeuthenab3e5652019-10-28 13:32:48 -040086 if (!data->loadFromDisk()) {
87 LOG(ERROR) << "Error loading data for credential";
88 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
89 "Error loading data for credential");
90 }
91
David Zeuthenab3e5652019-10-28 13:32:48 -040092 sp<IIdentityCredential> halBinder;
David Zeuthena6f9fba2020-02-11 22:08:27 -050093 Status status =
David Zeuthen472e6c82020-10-16 11:50:13 -040094 halStoreBinder_->getCredential(cipherSuite_, data->getCredentialData(), &halBinder);
David Zeuthena6f9fba2020-02-11 22:08:27 -050095 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
96 int code = status.serviceSpecificErrorCode();
97 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
98 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
99 }
100 }
101 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400102 LOG(ERROR) << "Error getting HAL binder";
103 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
104 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400105 halBinder_ = halBinder;
106
107 return Status::ok();
108}
109
110Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400111 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
112 if (!data->loadFromDisk()) {
113 LOG(ERROR) << "Error loading data for credential";
114 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
115 "Error loading data for credential");
116 }
117 *_aidl_return = data->getAttestationCertificate();
David Zeuthenab3e5652019-10-28 13:32:48 -0400118 return Status::ok();
119}
120
121// Returns operation handle
David Zeuthen472e6c82020-10-16 11:50:13 -0400122Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
123 int64_t* _aidl_return) {
124 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
125 if (!data->loadFromDisk()) {
126 LOG(ERROR) << "Error loading data for credential";
127 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
128 "Error loading data for credential");
129 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400130
David Zeuthen27407a52021-03-04 16:32:43 -0500131 // We just check if a key is available, we actually don't store it since we
132 // don't keep CredentialData around between binder calls.
133 const AuthKeyData* authKey =
134 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
135 if (authKey == nullptr) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400136 return Status::fromServiceSpecificError(
137 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
138 "No suitable authentication key available");
139 }
140
David Zeuthen27407a52021-03-04 16:32:43 -0500141 if (!ensureChallenge()) {
142 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
143 "Error getting challenge (bug in HAL or TA)");
144 }
145 *_aidl_return = selectedChallenge_;
146 return Status::ok();
147}
148
149bool Credential::ensureChallenge() {
150 if (selectedChallenge_ != 0) {
151 return true;
152 }
153
David Zeuthena6f9fba2020-02-11 22:08:27 -0500154 int64_t challenge;
155 Status status = halBinder_->createAuthChallenge(&challenge);
156 if (!status.isOk()) {
David Zeuthen27407a52021-03-04 16:32:43 -0500157 LOG(ERROR) << "Error getting challenge: " << status.exceptionMessage();
158 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400159 }
160 if (challenge == 0) {
David Zeuthen27407a52021-03-04 16:32:43 -0500161 LOG(ERROR) << "Returned challenge is 0 (bug in HAL or TA)";
162 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400163 }
164
165 selectedChallenge_ = challenge;
David Zeuthen27407a52021-03-04 16:32:43 -0500166 return true;
David Zeuthenab3e5652019-10-28 13:32:48 -0400167}
168
David Zeuthen59102f32020-05-08 10:58:09 -0400169class CredstoreTokenCallback : public android::security::keystore::BnCredstoreTokenCallback,
170 public promise<tuple<bool, vector<uint8_t>, vector<uint8_t>>> {
171 public:
172 CredstoreTokenCallback() {}
173 virtual Status onFinished(bool success, const vector<uint8_t>& authToken,
174 const vector<uint8_t>& verificationToken) override {
175 this->set_value({success, authToken, verificationToken});
176 return Status::ok();
177 }
178};
179
David Zeuthenab3e5652019-10-28 13:32:48 -0400180// Returns false if an error occurred communicating with keystore.
181//
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000182bool getTokensFromKeystore1(uint64_t challenge, uint64_t secureUserId,
183 unsigned int authTokenMaxAgeMillis,
184 AidlHardwareAuthToken& aidlAuthToken,
185 AidlVerificationToken& aidlVerificationToken) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400186 sp<IServiceManager> sm = defaultServiceManager();
187 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
188 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
189 if (keystore == nullptr) {
190 return false;
191 }
192
David Zeuthen59102f32020-05-08 10:58:09 -0400193 sp<CredstoreTokenCallback> callback = new CredstoreTokenCallback();
194 auto future = callback->get_future();
195
196 Status status =
197 keystore->getTokensForCredstore(challenge, secureUserId, authTokenMaxAgeMillis, callback);
198 if (!status.isOk()) {
199 return false;
200 }
201
202 auto fstatus = future.wait_for(std::chrono::milliseconds(5000));
203 if (fstatus != std::future_status::ready) {
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000204 LOG(ERROR) << "Waited 5 seconds for tokens from keystore, aborting";
David Zeuthen59102f32020-05-08 10:58:09 -0400205 return false;
206 }
207 auto [success, returnedAuthToken, returnedVerificationToken] = future.get();
208 if (!success) {
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000209 LOG(ERROR) << "Error getting tokens from keystore1";
David Zeuthenab3e5652019-10-28 13:32:48 -0400210 return false;
211 }
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000212 // It's entirely possible getTokensFromKeystore() succeeded but didn't
213 // return any tokens (in which case the returned byte-vectors are
214 // empty). For example, this can happen if no auth token is available
215 // which satifies e.g. |authTokenMaxAgeMillis|.
216 //
217 if (returnedAuthToken.size() > 0) {
218 HardwareAuthToken authToken =
219 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(returnedAuthToken);
220 // Convert from HIDL to AIDL...
221 aidlAuthToken.challenge = int64_t(authToken.challenge);
222 aidlAuthToken.userId = int64_t(authToken.userId);
223 aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
224 aidlAuthToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType(
225 int32_t(authToken.authenticatorType));
226 aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
227 aidlAuthToken.mac = authToken.mac;
228 }
229
230 if (returnedVerificationToken.size() > 0) {
231 optional<VerificationToken> token =
232 android::hardware::keymaster::V4_0::support::deserializeVerificationToken(
233 returnedVerificationToken);
234 if (!token) {
235 LOG(ERROR) << "Error deserializing verification token";
236 }
237 aidlVerificationToken.challenge = token->challenge;
238 aidlVerificationToken.timestamp.milliSeconds = token->timestamp;
239 aidlVerificationToken.securityLevel =
240 ::android::hardware::keymaster::SecurityLevel(token->securityLevel);
241 aidlVerificationToken.mac = token->mac;
242 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400243 return true;
244}
245
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000246// Returns false if an error occurred communicating with keystore.
247//
248bool getTokensFromKeystore2(uint64_t challenge, uint64_t secureUserId,
249 unsigned int authTokenMaxAgeMillis,
250 AidlHardwareAuthToken& aidlAuthToken,
251 AidlVerificationToken& aidlVerificationToken) {
252 // try to connect to IKeystoreAuthorization AIDL service first.
253 AIBinder* authzAIBinder = AServiceManager_checkService("android.security.authorization");
254 ::ndk::SpAIBinder authzBinder(authzAIBinder);
255 auto authzService = IKeystoreAuthorization::fromBinder(authzBinder);
256 if (authzService) {
257 AuthorizationTokens authzTokens;
258 auto result = authzService->getAuthTokensForCredStore(challenge, secureUserId,
259 authTokenMaxAgeMillis, &authzTokens);
260 // Convert KeyMint auth token to KeyMaster authtoken, only if tokens are
261 // returned
262 if (result.isOk()) {
263 KeyMintAuthToken keymintAuthToken = authzTokens.authToken;
264 aidlAuthToken.challenge = keymintAuthToken.challenge;
265 aidlAuthToken.userId = keymintAuthToken.userId;
266 aidlAuthToken.authenticatorId = keymintAuthToken.authenticatorId;
267 aidlAuthToken.authenticatorType =
268 ::android::hardware::keymaster::HardwareAuthenticatorType(
269 int32_t(keymintAuthToken.authenticatorType));
270 aidlAuthToken.timestamp.milliSeconds = keymintAuthToken.timestamp.milliSeconds;
271 aidlAuthToken.mac = keymintAuthToken.mac;
272
273 // Convert timestamp token to KeyMaster verification token
274 TimeStampToken timestampToken = authzTokens.timestampToken;
275 aidlVerificationToken.challenge = timestampToken.challenge;
276 aidlVerificationToken.timestamp.milliSeconds = timestampToken.timestamp.milliSeconds;
277 // Legacy verification tokens were always minted by TEE.
278 aidlVerificationToken.securityLevel = SecurityLevel::TRUSTED_ENVIRONMENT;
279 aidlVerificationToken.mac = timestampToken.mac;
280 } else {
281 if (result.getServiceSpecificError() == 0) {
282 // Here we differentiate the errors occurred during communication
283 // from the service specific errors.
284 LOG(ERROR) << "Error getting tokens from keystore2: " << result.getDescription();
285 return false;
286 } else {
Hasini Gunasinghe984c6302021-03-15 16:10:57 +0000287 // Log the reason for not receiving auth tokens from keystore2.
288 LOG(INFO) << "Auth tokens were not received due to: " << result.getDescription();
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000289 }
290 }
291 return true;
292 } else {
293 LOG(ERROR) << "Error connecting to IKeystoreAuthorization service";
294 return false;
295 }
296}
297
David Zeuthenab3e5652019-10-28 13:32:48 -0400298Status Credential::getEntries(const vector<uint8_t>& requestMessage,
299 const vector<RequestNamespaceParcel>& requestNamespaces,
300 const vector<uint8_t>& sessionTranscript,
301 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
David Zeuthen472e6c82020-10-16 11:50:13 -0400302 bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400303 GetEntriesResultParcel ret;
304
David Zeuthen472e6c82020-10-16 11:50:13 -0400305 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
306 if (!data->loadFromDisk()) {
307 LOG(ERROR) << "Error loading data for credential";
308 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
309 "Error loading data for credential");
310 }
311
David Zeuthenab3e5652019-10-28 13:32:48 -0400312 // Calculate requestCounts ahead of time and be careful not to include
313 // elements that don't exist.
314 //
315 // Also go through and figure out which access control profiles to include
316 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500317 vector<int32_t> requestCounts;
David Zeuthen472e6c82020-10-16 11:50:13 -0400318 const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
David Zeuthen52630002020-07-10 14:10:05 -0400319
320 // We don't support ACP identifiers which isn't in the range 0 to 31. This
321 // guarantee exists so it's feasible to implement the TA part of an Identity
322 // Credential HAL implementation where the TA uses a 32-bit word to indicate
323 // which profiles are authorized.
324 for (const SecureAccessControlProfile& profile : allProfiles) {
325 if (profile.id < 0 || profile.id >= 32) {
326 return Status::fromServiceSpecificError(
327 ICredentialStore::ERROR_GENERIC,
328 "Invalid accessProfileId in profile (must be between 0 and 31)");
329 }
330 }
331
332 vector<bool> includeProfile(32);
333
David Zeuthenab3e5652019-10-28 13:32:48 -0400334 for (const RequestNamespaceParcel& rns : requestNamespaces) {
335 size_t numEntriesInNsToRequest = 0;
336 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400337 if (data->hasEntryData(rns.namespaceName, rep.name)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400338 numEntriesInNsToRequest++;
339 }
340
David Zeuthen472e6c82020-10-16 11:50:13 -0400341 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
342 if (eData) {
343 for (int32_t id : eData.value().accessControlProfileIds) {
David Zeuthen52630002020-07-10 14:10:05 -0400344 if (id < 0 || id >= 32) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400345 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
346 << rns.namespaceName << ": " << rep.name;
347 return Status::fromServiceSpecificError(
David Zeuthen52630002020-07-10 14:10:05 -0400348 ICredentialStore::ERROR_GENERIC,
349 "Invalid accessProfileId in entry (must be between 0 and 31)");
David Zeuthenab3e5652019-10-28 13:32:48 -0400350 }
351 includeProfile[id] = true;
352 }
353 }
354 }
355 requestCounts.push_back(numEntriesInNsToRequest);
356 }
357
358 // Now that we know which profiles are needed, send only those to the
359 // HAL.
360 vector<SecureAccessControlProfile> selectedProfiles;
361 for (size_t n = 0; n < allProfiles.size(); n++) {
David Zeuthen52630002020-07-10 14:10:05 -0400362 if (includeProfile[allProfiles[n].id]) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400363 selectedProfiles.push_back(allProfiles[n]);
364 }
365 }
366
367 // Calculate the highest [1] non-zero timeout and if user-auth is needed
368 // ... we need this to select an appropriate authToken.
369 //
370 // [1] : Why do we request the highest timeout and not the lowest? Well, we
371 // return partial results in getEntries e.g. if some data elements
372 // fail to authorize we'll still return the ones that did not fail. So
373 // e.g. consider data elements A and B where A has an ACP with 60
374 // seconds and B has an ACP with 3600 seconds. In this case we'll be
375 // fine with getting an authToken for e.g. 2400 seconds which would
376 // mean returning only B.
377 //
378 bool userAuthNeeded = false;
379 unsigned int authTokenMaxAgeMillis = 0;
380 for (auto& profile : selectedProfiles) {
381 if (profile.userAuthenticationRequired) {
382 userAuthNeeded = true;
383 if (profile.timeoutMillis > 0) {
384 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
385 authTokenMaxAgeMillis = profile.timeoutMillis;
386 }
387 }
388 }
389 }
390
David Zeuthen59102f32020-05-08 10:58:09 -0400391 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
392 // is needed in any of the access control profiles for data items being requested.
393 //
David Zeuthena6f9fba2020-02-11 22:08:27 -0500394 AidlHardwareAuthToken aidlAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400395 AidlVerificationToken aidlVerificationToken;
396 aidlAuthToken.challenge = 0;
397 aidlAuthToken.userId = 0;
398 aidlAuthToken.authenticatorId = 0;
399 aidlAuthToken.authenticatorType =
400 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
401 aidlAuthToken.timestamp.milliSeconds = 0;
402 aidlAuthToken.mac.clear();
403 aidlVerificationToken.challenge = 0;
404 aidlVerificationToken.timestamp.milliSeconds = 0;
405 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
406 aidlVerificationToken.mac.clear();
David Zeuthenab3e5652019-10-28 13:32:48 -0400407 if (userAuthNeeded) {
David Zeuthen27407a52021-03-04 16:32:43 -0500408 // If user authentication is needed, always get a challenge from the
409 // HAL/TA since it'll need it to check the returned VerificationToken
410 // for freshness.
411 if (!ensureChallenge()) {
412 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
413 "Error getting challenge (bug in HAL or TA)");
414 }
415
416 // Note: if all selected profiles require auth-on-every-presentation
417 // then authTokenMaxAgeMillis will be 0 (because timeoutMillis for each
418 // profile is 0). Which means that keystore will only return an
419 // AuthToken if its challenge matches what we pass, regardless of its
420 // age. This is intended b/c the HAL/TA will check not care about
421 // the age in this case, it only cares that the challenge matches.
422 //
423 // Otherwise, if one or more of the profiles is auth-with-a-timeout then
424 // authTokenMaxAgeMillis will be set to the largest of those
425 // timeouts. We'll get an AuthToken which satisfies this deadline if it
426 // exists. This authToken _may_ have the requested challenge but it's
427 // not a guarantee and it's also not required.
428 //
429
Janis Danisevskis4c2b0412021-03-10 14:48:48 -0800430 std::optional<bool> keystore2_status = {true};
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000431 if (keystore2_status.has_value() && keystore2_status.value()) {
432 if (!getTokensFromKeystore2(selectedChallenge_, data->getSecureUserId(),
433 authTokenMaxAgeMillis, aidlAuthToken,
434 aidlVerificationToken)) {
435 LOG(ERROR) << "Error getting tokens from keystore2";
David Zeuthen59102f32020-05-08 10:58:09 -0400436 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000437 "Error getting tokens from keystore2");
David Zeuthen59102f32020-05-08 10:58:09 -0400438 }
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000439 } else {
440 if (!getTokensFromKeystore1(selectedChallenge_, data->getSecureUserId(),
441 authTokenMaxAgeMillis, aidlAuthToken,
442 aidlVerificationToken)) {
443 LOG(ERROR) << "Error getting tokens from keystore";
444 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
445 "Error getting tokens from keystore");
446 }
David Zeuthen59102f32020-05-08 10:58:09 -0400447 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400448 }
449
David Zeuthen55975ec2020-02-27 14:28:18 -0500450 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
451 // the Java layer. So we could end up with no previously selected auth key and we may
452 // need one.
David Zeuthen27407a52021-03-04 16:32:43 -0500453 //
454 const AuthKeyData* authKey =
455 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
456 if (authKey == nullptr) {
457 // If no authKey is available, consider it an error only when a
458 // SessionTranscript was provided.
459 //
460 // We allow no SessionTranscript to be provided because it makes
461 // the API simpler to deal with insofar it can be used without having
462 // to generate any authentication keys.
463 //
464 // In this "no SessionTranscript is provided" mode we don't return
465 // DeviceNameSpaces nor a MAC over DeviceAuthentication so we don't
466 // need a device key.
467 //
468 if (sessionTranscript.size() > 0) {
469 return Status::fromServiceSpecificError(
470 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
471 "No suitable authentication key available and one is needed");
David Zeuthen55975ec2020-02-27 14:28:18 -0500472 }
473 }
474 vector<uint8_t> signingKeyBlob;
475 if (authKey != nullptr) {
476 signingKeyBlob = authKey->keyBlob;
477 }
478
David Zeuthene2a78a42020-04-27 13:34:38 -0400479 // Pass the HAL enough information to allow calculating the size of
480 // DeviceNameSpaces ahead of time.
481 vector<RequestNamespace> halRequestNamespaces;
482 for (const RequestNamespaceParcel& rns : requestNamespaces) {
483 RequestNamespace ns;
484 ns.namespaceName = rns.namespaceName;
485 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400486 optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
David Zeuthene2a78a42020-04-27 13:34:38 -0400487 if (entryData) {
488 RequestDataItem di;
489 di.name = rep.name;
490 di.size = entryData.value().size;
491 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
492 ns.items.push_back(di);
493 }
494 }
495 if (ns.items.size() > 0) {
496 halRequestNamespaces.push_back(ns);
497 }
498 }
499 // This is not catastrophic, we might be dealing with a version 1 implementation which
500 // doesn't have this method.
501 Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces);
502 if (!status.isOk()) {
David Zeuthen59102f32020-05-08 10:58:09 -0400503 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
504 << "and continuing";
505 }
506
507 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
508 status = halBinder_->setVerificationToken(aidlVerificationToken);
509 if (!status.isOk()) {
510 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
David Zeuthene2a78a42020-04-27 13:34:38 -0400511 << "and continuing";
512 }
513
514 status =
David Zeuthen55975ec2020-02-27 14:28:18 -0500515 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
516 sessionTranscript, readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500517 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
518 int code = status.serviceSpecificErrorCode();
519 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
520 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
521 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
522 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
523 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
524 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
525 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
526 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
527 }
528 }
529 if (!status.isOk()) {
530 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400531 }
532
533 for (const RequestNamespaceParcel& rns : requestNamespaces) {
534 ResultNamespaceParcel resultNamespaceParcel;
535 resultNamespaceParcel.namespaceName = rns.namespaceName;
536
537 for (const RequestEntryParcel& rep : rns.entries) {
538 ResultEntryParcel resultEntryParcel;
539 resultEntryParcel.name = rep.name;
540
David Zeuthen472e6c82020-10-16 11:50:13 -0400541 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
542 if (!eData) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400543 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
544 resultNamespaceParcel.entries.push_back(resultEntryParcel);
545 continue;
546 }
547
David Zeuthena6f9fba2020-02-11 22:08:27 -0500548 status =
David Zeuthen472e6c82020-10-16 11:50:13 -0400549 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
550 eData.value().accessControlProfileIds);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500551 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
552 int code = status.serviceSpecificErrorCode();
553 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
554 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
555 resultNamespaceParcel.entries.push_back(resultEntryParcel);
556 continue;
557 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
558 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
559 resultNamespaceParcel.entries.push_back(resultEntryParcel);
560 continue;
561 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
562 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
563 resultNamespaceParcel.entries.push_back(resultEntryParcel);
564 continue;
565 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
566 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
567 resultNamespaceParcel.entries.push_back(resultEntryParcel);
568 continue;
569 }
570 }
571 if (!status.isOk()) {
572 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400573 }
574
575 vector<uint8_t> value;
David Zeuthen472e6c82020-10-16 11:50:13 -0400576 for (const auto& encryptedChunk : eData.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500577 vector<uint8_t> chunk;
578 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
579 if (!status.isOk()) {
580 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400581 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500582 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400583 }
584
585 resultEntryParcel.status = STATUS_OK;
586 resultEntryParcel.value = value;
587 resultNamespaceParcel.entries.push_back(resultEntryParcel);
588 }
589 ret.resultNamespaces.push_back(resultNamespaceParcel);
590 }
591
David Zeuthen55975ec2020-02-27 14:28:18 -0500592 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500593 if (!status.isOk()) {
594 return halStatusToGenericError(status);
595 }
596 if (authKey != nullptr) {
597 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400598 }
599
600 // Ensure useCount is updated on disk.
601 if (authKey != nullptr) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400602 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400603 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
604 "Error saving data");
605 }
606 }
607
608 *_aidl_return = ret;
609 return Status::ok();
610}
611
612Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500613 vector<uint8_t> proofOfDeletionSignature;
David Zeuthen472e6c82020-10-16 11:50:13 -0400614
615 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
616 if (!data->loadFromDisk()) {
617 LOG(ERROR) << "Error loading data for credential";
618 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
619 "Error loading data for credential");
620 }
621
David Zeuthena6f9fba2020-02-11 22:08:27 -0500622 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
623 if (!status.isOk()) {
624 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400625 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400626 if (!data->deleteCredential()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400627 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
628 "Error deleting credential data on disk");
629 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500630 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400631 return Status::ok();
632}
633
David Zeuthen472e6c82020-10-16 11:50:13 -0400634Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
635 vector<uint8_t>* _aidl_return) {
636 if (halApiVersion_ < 3) {
637 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
638 "Not implemented by HAL");
639 }
640 vector<uint8_t> proofOfDeletionSignature;
641
642 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
643 if (!data->loadFromDisk()) {
644 LOG(ERROR) << "Error loading data for credential";
645 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
646 "Error loading data for credential");
647 }
648
649 Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
650 if (!status.isOk()) {
651 return halStatusToGenericError(status);
652 }
653 if (!data->deleteCredential()) {
654 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
655 "Error deleting credential data on disk");
656 }
657 *_aidl_return = proofOfDeletionSignature;
658 return Status::ok();
659}
660
661Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
662 if (halApiVersion_ < 3) {
663 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
664 "Not implemented by HAL");
665 }
666 vector<uint8_t> proofOfOwnershipSignature;
667 Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
668 if (!status.isOk()) {
669 return halStatusToGenericError(status);
670 }
671 *_aidl_return = proofOfOwnershipSignature;
672 return Status::ok();
673}
674
David Zeuthenab3e5652019-10-28 13:32:48 -0400675Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400676 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500677 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
678 if (!status.isOk()) {
679 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400680 }
681
682 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
683 "ephemeralKey", // Alias for key
684 "0", // Serial, as a decimal number
685 "Credstore", // Issuer
686 "Ephemeral Key", // Subject
687 0, // Validity Not Before
688 24 * 60 * 60); // Validity Not After
689 if (!pkcs12Bytes) {
690 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
691 "Error creating PKCS#12 structure for key pair");
692 }
693 *_aidl_return = pkcs12Bytes.value();
694 return Status::ok();
695}
696
697Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500698 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
699 if (!status.isOk()) {
700 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400701 }
702 return Status::ok();
703}
704
705Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400706 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
707 if (!data->loadFromDisk()) {
708 LOG(ERROR) << "Error loading data for credential";
709 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
710 "Error loading data for credential");
711 }
712 data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
713 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400714 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
715 "Error saving data");
716 }
717 return Status::ok();
718}
719
720Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400721 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
722 if (!data->loadFromDisk()) {
723 LOG(ERROR) << "Error loading data for credential";
724 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
725 "Error loading data for credential");
726 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400727 optional<vector<vector<uint8_t>>> keysNeedingCert =
David Zeuthen472e6c82020-10-16 11:50:13 -0400728 data->getAuthKeysNeedingCertification(halBinder_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400729 if (!keysNeedingCert) {
730 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
731 "Error getting auth keys neededing certification");
732 }
733 vector<AuthKeyParcel> authKeyParcels;
734 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
735 AuthKeyParcel authKeyParcel;
736 authKeyParcel.x509cert = key;
737 authKeyParcels.push_back(authKeyParcel);
738 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400739 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400740 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
741 "Error saving data");
742 }
743 *_aidl_return = authKeyParcels;
744 return Status::ok();
745}
746
747Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
748 const vector<uint8_t>& staticAuthData) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400749 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
750 if (!data->loadFromDisk()) {
751 LOG(ERROR) << "Error loading data for credential";
752 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
753 "Error loading data for credential");
754 }
755 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
756 std::numeric_limits<int64_t>::max(), staticAuthData)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400757 return Status::fromServiceSpecificError(
758 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
759 "Error finding authentication key to store static "
760 "authentication data for");
761 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400762 if (!data->saveToDisk()) {
763 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
764 "Error saving data");
765 }
766 return Status::ok();
767}
768
769Status
770Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
771 int64_t expirationDateMillisSinceEpoch,
772 const vector<uint8_t>& staticAuthData) {
773 if (halApiVersion_ < 3) {
774 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
775 "Not implemented by HAL");
776 }
777 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
778 if (!data->loadFromDisk()) {
779 LOG(ERROR) << "Error loading data for credential";
780 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
781 "Error loading data for credential");
782 }
783 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
784 expirationDateMillisSinceEpoch, staticAuthData)) {
785 return Status::fromServiceSpecificError(
786 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
787 "Error finding authentication key to store static "
788 "authentication data for");
789 }
790 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400791 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
792 "Error saving data");
793 }
794 return Status::ok();
795}
796
797Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400798 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
799 if (!data->loadFromDisk()) {
800 LOG(ERROR) << "Error loading data for credential";
801 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
802 "Error loading data for credential");
803 }
804 const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
David Zeuthenab3e5652019-10-28 13:32:48 -0400805 vector<int32_t> ret;
806 for (const AuthKeyData& authKeyData : authKeyDatas) {
807 ret.push_back(authKeyData.useCount);
808 }
809 *_aidl_return = ret;
810 return Status::ok();
811}
812
David Zeuthen472e6c82020-10-16 11:50:13 -0400813optional<string> extractDocType(const vector<uint8_t>& credentialData) {
814 auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
815 if (item == nullptr) {
816 LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
817 return {};
818 }
819 const cppbor::Array* array = item->asArray();
820 if (array == nullptr || array->size() < 1) {
821 LOG(ERROR) << "CredentialData array with at least one element";
822 return {};
823 }
824 const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
825 if (tstr == nullptr) {
826 LOG(ERROR) << "First item in CredentialData is not a string";
827 return {};
828 }
829 return tstr->value();
830}
831
832Status Credential::update(sp<IWritableCredential>* _aidl_return) {
833 if (halApiVersion_ < 3) {
834 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
835 "Not implemented by HAL");
836 }
837 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
838 if (!data->loadFromDisk()) {
839 LOG(ERROR) << "Error loading data for credential";
840 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
841 "Error loading data for credential");
842 }
843
844 sp<IWritableIdentityCredential> halWritableCredential;
845 Status status = halBinder_->updateCredential(&halWritableCredential);
846 if (!status.isOk()) {
847 return halStatusToGenericError(status);
848 }
849
850 optional<string> docType = extractDocType(data->getCredentialData());
851 if (!docType) {
852 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
853 "Unable to extract DocType from CredentialData");
854 }
855
856 // NOTE: The caller is expected to call WritableCredential::personalize() which will
857 // write brand new data to disk, specifically it will overwrite any data already
858 // have _including_ authentication keys.
859 //
860 // It is because of this we need to set the CredentialKey certificate chain,
861 // keyCount, and maxUsesPerKey below.
David Zeuthen27407a52021-03-04 16:32:43 -0500862 sp<WritableCredential> writableCredential = new WritableCredential(
863 dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
David Zeuthen472e6c82020-10-16 11:50:13 -0400864
865 writableCredential->setAttestationCertificate(data->getAttestationCertificate());
866 auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
867 writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
868
David Zeuthen27407a52021-03-04 16:32:43 -0500869 // Because its data has changed, we need to replace the binder for the
870 // IIdentityCredential when the credential has been updated... otherwise the
871 // remote object will have stale data for future calls, for example
872 // getAuthKeysNeedingCertification().
David Zeuthen472e6c82020-10-16 11:50:13 -0400873 //
David Zeuthen27407a52021-03-04 16:32:43 -0500874 // The way this is implemented is that setCredentialToReloadWhenUpdated()
875 // instructs the WritableCredential to call writableCredentialPersonalized()
876 // on |this|.
David Zeuthen472e6c82020-10-16 11:50:13 -0400877 //
David Zeuthen27407a52021-03-04 16:32:43 -0500878 //
879 writableCredential->setCredentialToReloadWhenUpdated(this);
David Zeuthen472e6c82020-10-16 11:50:13 -0400880
881 *_aidl_return = writableCredential;
882 return Status::ok();
883}
884
David Zeuthen27407a52021-03-04 16:32:43 -0500885void Credential::writableCredentialPersonalized() {
886 Status status = ensureOrReplaceHalBinder();
887 if (!status.isOk()) {
888 LOG(ERROR) << "Error reloading credential";
889 }
890}
891
David Zeuthenab3e5652019-10-28 13:32:48 -0400892} // namespace identity
893} // namespace security
894} // namespace android