blob: 23e144f7a2e6bc2fa290246930a2c7d45ee47d07 [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>
40#include <android/sysprop/Keystore2Properties.sysprop.h>
41
David Zeuthenab3e5652019-10-28 13:32:48 -040042#include "Credential.h"
43#include "CredentialData.h"
44#include "Util.h"
David Zeuthen472e6c82020-10-16 11:50:13 -040045#include "WritableCredential.h"
David Zeuthenab3e5652019-10-28 13:32:48 -040046
47namespace android {
48namespace security {
49namespace identity {
50
51using std::optional;
David Zeuthen59102f32020-05-08 10:58:09 -040052using std::promise;
53using std::tuple;
David Zeuthenab3e5652019-10-28 13:32:48 -040054
55using android::security::keystore::IKeystoreService;
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000056using namespace android::sysprop;
David Zeuthenab3e5652019-10-28 13:32:48 -040057
David Zeuthen472e6c82020-10-16 11:50:13 -040058using ::android::hardware::identity::IWritableIdentityCredential;
59
David Zeuthenab3e5652019-10-28 13:32:48 -040060using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
61using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
62using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
63using ::android::hardware::identity::support::sha256;
64
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000065using android::hardware::keymaster::SecurityLevel;
David Zeuthenab3e5652019-10-28 13:32:48 -040066using android::hardware::keymaster::V4_0::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040067using android::hardware::keymaster::V4_0::VerificationToken;
David Zeuthena6f9fba2020-02-11 22:08:27 -050068using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040069using AidlVerificationToken = android::hardware::keymaster::VerificationToken;
David Zeuthenab3e5652019-10-28 13:32:48 -040070
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000071using KeyMintAuthToken = ::aidl::android::hardware::security::keymint::HardwareAuthToken;
72using ::aidl::android::hardware::security::secureclock::TimeStampToken;
73using ::aidl::android::security::authorization::AuthorizationTokens;
74using ::aidl::android::security::authorization::IKeystoreAuthorization;
75
David Zeuthena6f9fba2020-02-11 22:08:27 -050076Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
David Zeuthen472e6c82020-10-16 11:50:13 -040077 const std::string& credentialName, uid_t callingUid,
78 HardwareInformation hwInfo, sp<IIdentityCredentialStore> halStoreBinder,
79 int halApiVersion)
80 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName),
81 callingUid_(callingUid), hwInfo_(std::move(hwInfo)), halStoreBinder_(halStoreBinder),
82 halApiVersion_(halApiVersion) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040083
84Credential::~Credential() {}
85
David Zeuthen472e6c82020-10-16 11:50:13 -040086Status Credential::ensureOrReplaceHalBinder() {
87 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
David Zeuthenab3e5652019-10-28 13:32:48 -040088 if (!data->loadFromDisk()) {
89 LOG(ERROR) << "Error loading data for credential";
90 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
91 "Error loading data for credential");
92 }
93
David Zeuthenab3e5652019-10-28 13:32:48 -040094 sp<IIdentityCredential> halBinder;
David Zeuthena6f9fba2020-02-11 22:08:27 -050095 Status status =
David Zeuthen472e6c82020-10-16 11:50:13 -040096 halStoreBinder_->getCredential(cipherSuite_, data->getCredentialData(), &halBinder);
David Zeuthena6f9fba2020-02-11 22:08:27 -050097 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
98 int code = status.serviceSpecificErrorCode();
99 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
100 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
101 }
102 }
103 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400104 LOG(ERROR) << "Error getting HAL binder";
105 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
106 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400107 halBinder_ = halBinder;
108
109 return Status::ok();
110}
111
112Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400113 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
114 if (!data->loadFromDisk()) {
115 LOG(ERROR) << "Error loading data for credential";
116 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
117 "Error loading data for credential");
118 }
119 *_aidl_return = data->getAttestationCertificate();
David Zeuthenab3e5652019-10-28 13:32:48 -0400120 return Status::ok();
121}
122
123// Returns operation handle
David Zeuthen472e6c82020-10-16 11:50:13 -0400124Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
125 int64_t* _aidl_return) {
126 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
127 if (!data->loadFromDisk()) {
128 LOG(ERROR) << "Error loading data for credential";
129 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
130 "Error loading data for credential");
131 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400132
David Zeuthen27407a52021-03-04 16:32:43 -0500133 // We just check if a key is available, we actually don't store it since we
134 // don't keep CredentialData around between binder calls.
135 const AuthKeyData* authKey =
136 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
137 if (authKey == nullptr) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400138 return Status::fromServiceSpecificError(
139 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
140 "No suitable authentication key available");
141 }
142
David Zeuthen27407a52021-03-04 16:32:43 -0500143 if (!ensureChallenge()) {
144 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
145 "Error getting challenge (bug in HAL or TA)");
146 }
147 *_aidl_return = selectedChallenge_;
148 return Status::ok();
149}
150
151bool Credential::ensureChallenge() {
152 if (selectedChallenge_ != 0) {
153 return true;
154 }
155
David Zeuthena6f9fba2020-02-11 22:08:27 -0500156 int64_t challenge;
157 Status status = halBinder_->createAuthChallenge(&challenge);
158 if (!status.isOk()) {
David Zeuthen27407a52021-03-04 16:32:43 -0500159 LOG(ERROR) << "Error getting challenge: " << status.exceptionMessage();
160 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400161 }
162 if (challenge == 0) {
David Zeuthen27407a52021-03-04 16:32:43 -0500163 LOG(ERROR) << "Returned challenge is 0 (bug in HAL or TA)";
164 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400165 }
166
167 selectedChallenge_ = challenge;
David Zeuthen27407a52021-03-04 16:32:43 -0500168 return true;
David Zeuthenab3e5652019-10-28 13:32:48 -0400169}
170
David Zeuthen59102f32020-05-08 10:58:09 -0400171class CredstoreTokenCallback : public android::security::keystore::BnCredstoreTokenCallback,
172 public promise<tuple<bool, vector<uint8_t>, vector<uint8_t>>> {
173 public:
174 CredstoreTokenCallback() {}
175 virtual Status onFinished(bool success, const vector<uint8_t>& authToken,
176 const vector<uint8_t>& verificationToken) override {
177 this->set_value({success, authToken, verificationToken});
178 return Status::ok();
179 }
180};
181
David Zeuthenab3e5652019-10-28 13:32:48 -0400182// Returns false if an error occurred communicating with keystore.
183//
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000184bool getTokensFromKeystore1(uint64_t challenge, uint64_t secureUserId,
185 unsigned int authTokenMaxAgeMillis,
186 AidlHardwareAuthToken& aidlAuthToken,
187 AidlVerificationToken& aidlVerificationToken) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400188 sp<IServiceManager> sm = defaultServiceManager();
189 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
190 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
191 if (keystore == nullptr) {
192 return false;
193 }
194
David Zeuthen59102f32020-05-08 10:58:09 -0400195 sp<CredstoreTokenCallback> callback = new CredstoreTokenCallback();
196 auto future = callback->get_future();
197
198 Status status =
199 keystore->getTokensForCredstore(challenge, secureUserId, authTokenMaxAgeMillis, callback);
200 if (!status.isOk()) {
201 return false;
202 }
203
204 auto fstatus = future.wait_for(std::chrono::milliseconds(5000));
205 if (fstatus != std::future_status::ready) {
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000206 LOG(ERROR) << "Waited 5 seconds for tokens from keystore, aborting";
David Zeuthen59102f32020-05-08 10:58:09 -0400207 return false;
208 }
209 auto [success, returnedAuthToken, returnedVerificationToken] = future.get();
210 if (!success) {
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000211 LOG(ERROR) << "Error getting tokens from keystore1";
David Zeuthenab3e5652019-10-28 13:32:48 -0400212 return false;
213 }
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000214 // It's entirely possible getTokensFromKeystore() succeeded but didn't
215 // return any tokens (in which case the returned byte-vectors are
216 // empty). For example, this can happen if no auth token is available
217 // which satifies e.g. |authTokenMaxAgeMillis|.
218 //
219 if (returnedAuthToken.size() > 0) {
220 HardwareAuthToken authToken =
221 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(returnedAuthToken);
222 // Convert from HIDL to AIDL...
223 aidlAuthToken.challenge = int64_t(authToken.challenge);
224 aidlAuthToken.userId = int64_t(authToken.userId);
225 aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
226 aidlAuthToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType(
227 int32_t(authToken.authenticatorType));
228 aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
229 aidlAuthToken.mac = authToken.mac;
230 }
231
232 if (returnedVerificationToken.size() > 0) {
233 optional<VerificationToken> token =
234 android::hardware::keymaster::V4_0::support::deserializeVerificationToken(
235 returnedVerificationToken);
236 if (!token) {
237 LOG(ERROR) << "Error deserializing verification token";
238 }
239 aidlVerificationToken.challenge = token->challenge;
240 aidlVerificationToken.timestamp.milliSeconds = token->timestamp;
241 aidlVerificationToken.securityLevel =
242 ::android::hardware::keymaster::SecurityLevel(token->securityLevel);
243 aidlVerificationToken.mac = token->mac;
244 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400245 return true;
246}
247
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000248// Returns false if an error occurred communicating with keystore.
249//
250bool getTokensFromKeystore2(uint64_t challenge, uint64_t secureUserId,
251 unsigned int authTokenMaxAgeMillis,
252 AidlHardwareAuthToken& aidlAuthToken,
253 AidlVerificationToken& aidlVerificationToken) {
254 // try to connect to IKeystoreAuthorization AIDL service first.
255 AIBinder* authzAIBinder = AServiceManager_checkService("android.security.authorization");
256 ::ndk::SpAIBinder authzBinder(authzAIBinder);
257 auto authzService = IKeystoreAuthorization::fromBinder(authzBinder);
258 if (authzService) {
259 AuthorizationTokens authzTokens;
260 auto result = authzService->getAuthTokensForCredStore(challenge, secureUserId,
261 authTokenMaxAgeMillis, &authzTokens);
262 // Convert KeyMint auth token to KeyMaster authtoken, only if tokens are
263 // returned
264 if (result.isOk()) {
265 KeyMintAuthToken keymintAuthToken = authzTokens.authToken;
266 aidlAuthToken.challenge = keymintAuthToken.challenge;
267 aidlAuthToken.userId = keymintAuthToken.userId;
268 aidlAuthToken.authenticatorId = keymintAuthToken.authenticatorId;
269 aidlAuthToken.authenticatorType =
270 ::android::hardware::keymaster::HardwareAuthenticatorType(
271 int32_t(keymintAuthToken.authenticatorType));
272 aidlAuthToken.timestamp.milliSeconds = keymintAuthToken.timestamp.milliSeconds;
273 aidlAuthToken.mac = keymintAuthToken.mac;
274
275 // Convert timestamp token to KeyMaster verification token
276 TimeStampToken timestampToken = authzTokens.timestampToken;
277 aidlVerificationToken.challenge = timestampToken.challenge;
278 aidlVerificationToken.timestamp.milliSeconds = timestampToken.timestamp.milliSeconds;
279 // Legacy verification tokens were always minted by TEE.
280 aidlVerificationToken.securityLevel = SecurityLevel::TRUSTED_ENVIRONMENT;
281 aidlVerificationToken.mac = timestampToken.mac;
282 } else {
283 if (result.getServiceSpecificError() == 0) {
284 // Here we differentiate the errors occurred during communication
285 // from the service specific errors.
286 LOG(ERROR) << "Error getting tokens from keystore2: " << result.getDescription();
287 return false;
288 } else {
Hasini Gunasinghe984c6302021-03-15 16:10:57 +0000289 // Log the reason for not receiving auth tokens from keystore2.
290 LOG(INFO) << "Auth tokens were not received due to: " << result.getDescription();
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000291 }
292 }
293 return true;
294 } else {
295 LOG(ERROR) << "Error connecting to IKeystoreAuthorization service";
296 return false;
297 }
298}
299
David Zeuthenab3e5652019-10-28 13:32:48 -0400300Status Credential::getEntries(const vector<uint8_t>& requestMessage,
301 const vector<RequestNamespaceParcel>& requestNamespaces,
302 const vector<uint8_t>& sessionTranscript,
303 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
David Zeuthen472e6c82020-10-16 11:50:13 -0400304 bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400305 GetEntriesResultParcel ret;
306
David Zeuthen472e6c82020-10-16 11:50:13 -0400307 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
308 if (!data->loadFromDisk()) {
309 LOG(ERROR) << "Error loading data for credential";
310 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
311 "Error loading data for credential");
312 }
313
David Zeuthenab3e5652019-10-28 13:32:48 -0400314 // Calculate requestCounts ahead of time and be careful not to include
315 // elements that don't exist.
316 //
317 // Also go through and figure out which access control profiles to include
318 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500319 vector<int32_t> requestCounts;
David Zeuthen472e6c82020-10-16 11:50:13 -0400320 const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
David Zeuthen52630002020-07-10 14:10:05 -0400321
322 // We don't support ACP identifiers which isn't in the range 0 to 31. This
323 // guarantee exists so it's feasible to implement the TA part of an Identity
324 // Credential HAL implementation where the TA uses a 32-bit word to indicate
325 // which profiles are authorized.
326 for (const SecureAccessControlProfile& profile : allProfiles) {
327 if (profile.id < 0 || profile.id >= 32) {
328 return Status::fromServiceSpecificError(
329 ICredentialStore::ERROR_GENERIC,
330 "Invalid accessProfileId in profile (must be between 0 and 31)");
331 }
332 }
333
334 vector<bool> includeProfile(32);
335
David Zeuthenab3e5652019-10-28 13:32:48 -0400336 for (const RequestNamespaceParcel& rns : requestNamespaces) {
337 size_t numEntriesInNsToRequest = 0;
338 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400339 if (data->hasEntryData(rns.namespaceName, rep.name)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400340 numEntriesInNsToRequest++;
341 }
342
David Zeuthen472e6c82020-10-16 11:50:13 -0400343 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
344 if (eData) {
345 for (int32_t id : eData.value().accessControlProfileIds) {
David Zeuthen52630002020-07-10 14:10:05 -0400346 if (id < 0 || id >= 32) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400347 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
348 << rns.namespaceName << ": " << rep.name;
349 return Status::fromServiceSpecificError(
David Zeuthen52630002020-07-10 14:10:05 -0400350 ICredentialStore::ERROR_GENERIC,
351 "Invalid accessProfileId in entry (must be between 0 and 31)");
David Zeuthenab3e5652019-10-28 13:32:48 -0400352 }
353 includeProfile[id] = true;
354 }
355 }
356 }
357 requestCounts.push_back(numEntriesInNsToRequest);
358 }
359
360 // Now that we know which profiles are needed, send only those to the
361 // HAL.
362 vector<SecureAccessControlProfile> selectedProfiles;
363 for (size_t n = 0; n < allProfiles.size(); n++) {
David Zeuthen52630002020-07-10 14:10:05 -0400364 if (includeProfile[allProfiles[n].id]) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400365 selectedProfiles.push_back(allProfiles[n]);
366 }
367 }
368
369 // Calculate the highest [1] non-zero timeout and if user-auth is needed
370 // ... we need this to select an appropriate authToken.
371 //
372 // [1] : Why do we request the highest timeout and not the lowest? Well, we
373 // return partial results in getEntries e.g. if some data elements
374 // fail to authorize we'll still return the ones that did not fail. So
375 // e.g. consider data elements A and B where A has an ACP with 60
376 // seconds and B has an ACP with 3600 seconds. In this case we'll be
377 // fine with getting an authToken for e.g. 2400 seconds which would
378 // mean returning only B.
379 //
380 bool userAuthNeeded = false;
381 unsigned int authTokenMaxAgeMillis = 0;
382 for (auto& profile : selectedProfiles) {
383 if (profile.userAuthenticationRequired) {
384 userAuthNeeded = true;
385 if (profile.timeoutMillis > 0) {
386 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
387 authTokenMaxAgeMillis = profile.timeoutMillis;
388 }
389 }
390 }
391 }
392
David Zeuthen59102f32020-05-08 10:58:09 -0400393 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
394 // is needed in any of the access control profiles for data items being requested.
395 //
David Zeuthena6f9fba2020-02-11 22:08:27 -0500396 AidlHardwareAuthToken aidlAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400397 AidlVerificationToken aidlVerificationToken;
398 aidlAuthToken.challenge = 0;
399 aidlAuthToken.userId = 0;
400 aidlAuthToken.authenticatorId = 0;
401 aidlAuthToken.authenticatorType =
402 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
403 aidlAuthToken.timestamp.milliSeconds = 0;
404 aidlAuthToken.mac.clear();
405 aidlVerificationToken.challenge = 0;
406 aidlVerificationToken.timestamp.milliSeconds = 0;
407 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
408 aidlVerificationToken.mac.clear();
David Zeuthenab3e5652019-10-28 13:32:48 -0400409 if (userAuthNeeded) {
David Zeuthen27407a52021-03-04 16:32:43 -0500410 // If user authentication is needed, always get a challenge from the
411 // HAL/TA since it'll need it to check the returned VerificationToken
412 // for freshness.
413 if (!ensureChallenge()) {
414 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
415 "Error getting challenge (bug in HAL or TA)");
416 }
417
418 // Note: if all selected profiles require auth-on-every-presentation
419 // then authTokenMaxAgeMillis will be 0 (because timeoutMillis for each
420 // profile is 0). Which means that keystore will only return an
421 // AuthToken if its challenge matches what we pass, regardless of its
422 // age. This is intended b/c the HAL/TA will check not care about
423 // the age in this case, it only cares that the challenge matches.
424 //
425 // Otherwise, if one or more of the profiles is auth-with-a-timeout then
426 // authTokenMaxAgeMillis will be set to the largest of those
427 // timeouts. We'll get an AuthToken which satisfies this deadline if it
428 // exists. This authToken _may_ have the requested challenge but it's
429 // not a guarantee and it's also not required.
430 //
431
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000432 auto keystore2_status = Keystore2Properties::keystore2_enabled();
433 if (keystore2_status.has_value() && keystore2_status.value()) {
434 if (!getTokensFromKeystore2(selectedChallenge_, data->getSecureUserId(),
435 authTokenMaxAgeMillis, aidlAuthToken,
436 aidlVerificationToken)) {
437 LOG(ERROR) << "Error getting tokens from keystore2";
David Zeuthen59102f32020-05-08 10:58:09 -0400438 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000439 "Error getting tokens from keystore2");
David Zeuthen59102f32020-05-08 10:58:09 -0400440 }
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000441 } else {
442 if (!getTokensFromKeystore1(selectedChallenge_, data->getSecureUserId(),
443 authTokenMaxAgeMillis, aidlAuthToken,
444 aidlVerificationToken)) {
445 LOG(ERROR) << "Error getting tokens from keystore";
446 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
447 "Error getting tokens from keystore");
448 }
David Zeuthen59102f32020-05-08 10:58:09 -0400449 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400450 }
451
David Zeuthen55975ec2020-02-27 14:28:18 -0500452 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
453 // the Java layer. So we could end up with no previously selected auth key and we may
454 // need one.
David Zeuthen27407a52021-03-04 16:32:43 -0500455 //
456 const AuthKeyData* authKey =
457 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
458 if (authKey == nullptr) {
459 // If no authKey is available, consider it an error only when a
460 // SessionTranscript was provided.
461 //
462 // We allow no SessionTranscript to be provided because it makes
463 // the API simpler to deal with insofar it can be used without having
464 // to generate any authentication keys.
465 //
466 // In this "no SessionTranscript is provided" mode we don't return
467 // DeviceNameSpaces nor a MAC over DeviceAuthentication so we don't
468 // need a device key.
469 //
470 if (sessionTranscript.size() > 0) {
471 return Status::fromServiceSpecificError(
472 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
473 "No suitable authentication key available and one is needed");
David Zeuthen55975ec2020-02-27 14:28:18 -0500474 }
475 }
476 vector<uint8_t> signingKeyBlob;
477 if (authKey != nullptr) {
478 signingKeyBlob = authKey->keyBlob;
479 }
480
David Zeuthene2a78a42020-04-27 13:34:38 -0400481 // Pass the HAL enough information to allow calculating the size of
482 // DeviceNameSpaces ahead of time.
483 vector<RequestNamespace> halRequestNamespaces;
484 for (const RequestNamespaceParcel& rns : requestNamespaces) {
485 RequestNamespace ns;
486 ns.namespaceName = rns.namespaceName;
487 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400488 optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
David Zeuthene2a78a42020-04-27 13:34:38 -0400489 if (entryData) {
490 RequestDataItem di;
491 di.name = rep.name;
492 di.size = entryData.value().size;
493 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
494 ns.items.push_back(di);
495 }
496 }
497 if (ns.items.size() > 0) {
498 halRequestNamespaces.push_back(ns);
499 }
500 }
501 // This is not catastrophic, we might be dealing with a version 1 implementation which
502 // doesn't have this method.
503 Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces);
504 if (!status.isOk()) {
David Zeuthen59102f32020-05-08 10:58:09 -0400505 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
506 << "and continuing";
507 }
508
509 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
510 status = halBinder_->setVerificationToken(aidlVerificationToken);
511 if (!status.isOk()) {
512 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
David Zeuthene2a78a42020-04-27 13:34:38 -0400513 << "and continuing";
514 }
515
516 status =
David Zeuthen55975ec2020-02-27 14:28:18 -0500517 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
518 sessionTranscript, readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500519 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
520 int code = status.serviceSpecificErrorCode();
521 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
522 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
523 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
524 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
525 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
526 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
527 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
528 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
529 }
530 }
531 if (!status.isOk()) {
532 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400533 }
534
535 for (const RequestNamespaceParcel& rns : requestNamespaces) {
536 ResultNamespaceParcel resultNamespaceParcel;
537 resultNamespaceParcel.namespaceName = rns.namespaceName;
538
539 for (const RequestEntryParcel& rep : rns.entries) {
540 ResultEntryParcel resultEntryParcel;
541 resultEntryParcel.name = rep.name;
542
David Zeuthen472e6c82020-10-16 11:50:13 -0400543 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
544 if (!eData) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400545 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
546 resultNamespaceParcel.entries.push_back(resultEntryParcel);
547 continue;
548 }
549
David Zeuthena6f9fba2020-02-11 22:08:27 -0500550 status =
David Zeuthen472e6c82020-10-16 11:50:13 -0400551 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
552 eData.value().accessControlProfileIds);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500553 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
554 int code = status.serviceSpecificErrorCode();
555 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
556 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
557 resultNamespaceParcel.entries.push_back(resultEntryParcel);
558 continue;
559 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
560 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
561 resultNamespaceParcel.entries.push_back(resultEntryParcel);
562 continue;
563 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
564 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
565 resultNamespaceParcel.entries.push_back(resultEntryParcel);
566 continue;
567 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
568 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
569 resultNamespaceParcel.entries.push_back(resultEntryParcel);
570 continue;
571 }
572 }
573 if (!status.isOk()) {
574 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400575 }
576
577 vector<uint8_t> value;
David Zeuthen472e6c82020-10-16 11:50:13 -0400578 for (const auto& encryptedChunk : eData.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500579 vector<uint8_t> chunk;
580 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
581 if (!status.isOk()) {
582 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400583 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500584 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400585 }
586
587 resultEntryParcel.status = STATUS_OK;
588 resultEntryParcel.value = value;
589 resultNamespaceParcel.entries.push_back(resultEntryParcel);
590 }
591 ret.resultNamespaces.push_back(resultNamespaceParcel);
592 }
593
David Zeuthen55975ec2020-02-27 14:28:18 -0500594 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500595 if (!status.isOk()) {
596 return halStatusToGenericError(status);
597 }
598 if (authKey != nullptr) {
599 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400600 }
601
602 // Ensure useCount is updated on disk.
603 if (authKey != nullptr) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400604 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400605 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
606 "Error saving data");
607 }
608 }
609
610 *_aidl_return = ret;
611 return Status::ok();
612}
613
614Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500615 vector<uint8_t> proofOfDeletionSignature;
David Zeuthen472e6c82020-10-16 11:50:13 -0400616
617 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
618 if (!data->loadFromDisk()) {
619 LOG(ERROR) << "Error loading data for credential";
620 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
621 "Error loading data for credential");
622 }
623
David Zeuthena6f9fba2020-02-11 22:08:27 -0500624 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
625 if (!status.isOk()) {
626 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400627 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400628 if (!data->deleteCredential()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400629 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
630 "Error deleting credential data on disk");
631 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500632 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400633 return Status::ok();
634}
635
David Zeuthen472e6c82020-10-16 11:50:13 -0400636Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
637 vector<uint8_t>* _aidl_return) {
638 if (halApiVersion_ < 3) {
639 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
640 "Not implemented by HAL");
641 }
642 vector<uint8_t> proofOfDeletionSignature;
643
644 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
645 if (!data->loadFromDisk()) {
646 LOG(ERROR) << "Error loading data for credential";
647 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
648 "Error loading data for credential");
649 }
650
651 Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
652 if (!status.isOk()) {
653 return halStatusToGenericError(status);
654 }
655 if (!data->deleteCredential()) {
656 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
657 "Error deleting credential data on disk");
658 }
659 *_aidl_return = proofOfDeletionSignature;
660 return Status::ok();
661}
662
663Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
664 if (halApiVersion_ < 3) {
665 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
666 "Not implemented by HAL");
667 }
668 vector<uint8_t> proofOfOwnershipSignature;
669 Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
670 if (!status.isOk()) {
671 return halStatusToGenericError(status);
672 }
673 *_aidl_return = proofOfOwnershipSignature;
674 return Status::ok();
675}
676
David Zeuthenab3e5652019-10-28 13:32:48 -0400677Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400678 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500679 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
680 if (!status.isOk()) {
681 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400682 }
683
684 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
685 "ephemeralKey", // Alias for key
686 "0", // Serial, as a decimal number
687 "Credstore", // Issuer
688 "Ephemeral Key", // Subject
689 0, // Validity Not Before
690 24 * 60 * 60); // Validity Not After
691 if (!pkcs12Bytes) {
692 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
693 "Error creating PKCS#12 structure for key pair");
694 }
695 *_aidl_return = pkcs12Bytes.value();
696 return Status::ok();
697}
698
699Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500700 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
701 if (!status.isOk()) {
702 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400703 }
704 return Status::ok();
705}
706
707Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400708 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
709 if (!data->loadFromDisk()) {
710 LOG(ERROR) << "Error loading data for credential";
711 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
712 "Error loading data for credential");
713 }
714 data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
715 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400716 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
717 "Error saving data");
718 }
719 return Status::ok();
720}
721
722Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400723 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
724 if (!data->loadFromDisk()) {
725 LOG(ERROR) << "Error loading data for credential";
726 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
727 "Error loading data for credential");
728 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400729 optional<vector<vector<uint8_t>>> keysNeedingCert =
David Zeuthen472e6c82020-10-16 11:50:13 -0400730 data->getAuthKeysNeedingCertification(halBinder_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400731 if (!keysNeedingCert) {
732 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
733 "Error getting auth keys neededing certification");
734 }
735 vector<AuthKeyParcel> authKeyParcels;
736 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
737 AuthKeyParcel authKeyParcel;
738 authKeyParcel.x509cert = key;
739 authKeyParcels.push_back(authKeyParcel);
740 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400741 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400742 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
743 "Error saving data");
744 }
745 *_aidl_return = authKeyParcels;
746 return Status::ok();
747}
748
749Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
750 const vector<uint8_t>& staticAuthData) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400751 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
752 if (!data->loadFromDisk()) {
753 LOG(ERROR) << "Error loading data for credential";
754 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
755 "Error loading data for credential");
756 }
757 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
758 std::numeric_limits<int64_t>::max(), staticAuthData)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400759 return Status::fromServiceSpecificError(
760 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
761 "Error finding authentication key to store static "
762 "authentication data for");
763 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400764 if (!data->saveToDisk()) {
765 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
766 "Error saving data");
767 }
768 return Status::ok();
769}
770
771Status
772Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
773 int64_t expirationDateMillisSinceEpoch,
774 const vector<uint8_t>& staticAuthData) {
775 if (halApiVersion_ < 3) {
776 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
777 "Not implemented by HAL");
778 }
779 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
780 if (!data->loadFromDisk()) {
781 LOG(ERROR) << "Error loading data for credential";
782 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
783 "Error loading data for credential");
784 }
785 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
786 expirationDateMillisSinceEpoch, staticAuthData)) {
787 return Status::fromServiceSpecificError(
788 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
789 "Error finding authentication key to store static "
790 "authentication data for");
791 }
792 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400793 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
794 "Error saving data");
795 }
796 return Status::ok();
797}
798
799Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400800 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
801 if (!data->loadFromDisk()) {
802 LOG(ERROR) << "Error loading data for credential";
803 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
804 "Error loading data for credential");
805 }
806 const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
David Zeuthenab3e5652019-10-28 13:32:48 -0400807 vector<int32_t> ret;
808 for (const AuthKeyData& authKeyData : authKeyDatas) {
809 ret.push_back(authKeyData.useCount);
810 }
811 *_aidl_return = ret;
812 return Status::ok();
813}
814
David Zeuthen472e6c82020-10-16 11:50:13 -0400815optional<string> extractDocType(const vector<uint8_t>& credentialData) {
816 auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
817 if (item == nullptr) {
818 LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
819 return {};
820 }
821 const cppbor::Array* array = item->asArray();
822 if (array == nullptr || array->size() < 1) {
823 LOG(ERROR) << "CredentialData array with at least one element";
824 return {};
825 }
826 const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
827 if (tstr == nullptr) {
828 LOG(ERROR) << "First item in CredentialData is not a string";
829 return {};
830 }
831 return tstr->value();
832}
833
834Status Credential::update(sp<IWritableCredential>* _aidl_return) {
835 if (halApiVersion_ < 3) {
836 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
837 "Not implemented by HAL");
838 }
839 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
840 if (!data->loadFromDisk()) {
841 LOG(ERROR) << "Error loading data for credential";
842 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
843 "Error loading data for credential");
844 }
845
846 sp<IWritableIdentityCredential> halWritableCredential;
847 Status status = halBinder_->updateCredential(&halWritableCredential);
848 if (!status.isOk()) {
849 return halStatusToGenericError(status);
850 }
851
852 optional<string> docType = extractDocType(data->getCredentialData());
853 if (!docType) {
854 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
855 "Unable to extract DocType from CredentialData");
856 }
857
858 // NOTE: The caller is expected to call WritableCredential::personalize() which will
859 // write brand new data to disk, specifically it will overwrite any data already
860 // have _including_ authentication keys.
861 //
862 // It is because of this we need to set the CredentialKey certificate chain,
863 // keyCount, and maxUsesPerKey below.
David Zeuthen27407a52021-03-04 16:32:43 -0500864 sp<WritableCredential> writableCredential = new WritableCredential(
865 dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
David Zeuthen472e6c82020-10-16 11:50:13 -0400866
867 writableCredential->setAttestationCertificate(data->getAttestationCertificate());
868 auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
869 writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
870
David Zeuthen27407a52021-03-04 16:32:43 -0500871 // Because its data has changed, we need to replace the binder for the
872 // IIdentityCredential when the credential has been updated... otherwise the
873 // remote object will have stale data for future calls, for example
874 // getAuthKeysNeedingCertification().
David Zeuthen472e6c82020-10-16 11:50:13 -0400875 //
David Zeuthen27407a52021-03-04 16:32:43 -0500876 // The way this is implemented is that setCredentialToReloadWhenUpdated()
877 // instructs the WritableCredential to call writableCredentialPersonalized()
878 // on |this|.
David Zeuthen472e6c82020-10-16 11:50:13 -0400879 //
David Zeuthen27407a52021-03-04 16:32:43 -0500880 //
881 writableCredential->setCredentialToReloadWhenUpdated(this);
David Zeuthen472e6c82020-10-16 11:50:13 -0400882
883 *_aidl_return = writableCredential;
884 return Status::ok();
885}
886
David Zeuthen27407a52021-03-04 16:32:43 -0500887void Credential::writableCredentialPersonalized() {
888 Status status = ensureOrReplaceHalBinder();
889 if (!status.isOk()) {
890 LOG(ERROR) << "Error reloading credential";
891 }
892}
893
David Zeuthenab3e5652019-10-28 13:32:48 -0400894} // namespace identity
895} // namespace security
896} // namespace android