blob: cbeb508419c9e1485902c733bbefbdddf2752b44 [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
David Zeuthen62d43bf2021-03-31 10:41:27 -040017#define LOG_TAG "credstore"
David Zeuthenab3e5652019-10-28 13:32:48 -040018
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 Zeuthenab3e5652019-10-28 13:32:48 -040025#include <binder/IPCThreadState.h>
26#include <binder/IServiceManager.h>
27#include <keymasterV4_0/keymaster_utils.h>
28
29#include <cppbor.h>
30#include <cppbor_parse.h>
David Zeuthen59102f32020-05-08 10:58:09 -040031#include <future>
32#include <tuple>
David Zeuthenab3e5652019-10-28 13:32:48 -040033
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000034#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
35#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
36#include <aidl/android/security/authorization/AuthorizationTokens.h>
37#include <aidl/android/security/authorization/IKeystoreAuthorization.h>
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000038
David Zeuthenab3e5652019-10-28 13:32:48 -040039#include "Credential.h"
40#include "CredentialData.h"
41#include "Util.h"
David Zeuthen472e6c82020-10-16 11:50:13 -040042#include "WritableCredential.h"
David Zeuthenab3e5652019-10-28 13:32:48 -040043
44namespace android {
45namespace security {
46namespace identity {
47
48using std::optional;
David Zeuthen59102f32020-05-08 10:58:09 -040049using std::promise;
50using std::tuple;
David Zeuthenab3e5652019-10-28 13:32:48 -040051
David Zeuthen472e6c82020-10-16 11:50:13 -040052using ::android::hardware::identity::IWritableIdentityCredential;
53
David Zeuthenab3e5652019-10-28 13:32:48 -040054using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
55using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
56using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
57using ::android::hardware::identity::support::sha256;
58
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000059using android::hardware::keymaster::SecurityLevel;
David Zeuthenab3e5652019-10-28 13:32:48 -040060using android::hardware::keymaster::V4_0::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040061using android::hardware::keymaster::V4_0::VerificationToken;
David Zeuthena6f9fba2020-02-11 22:08:27 -050062using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040063using AidlVerificationToken = android::hardware::keymaster::VerificationToken;
David Zeuthenab3e5652019-10-28 13:32:48 -040064
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +000065using KeyMintAuthToken = ::aidl::android::hardware::security::keymint::HardwareAuthToken;
66using ::aidl::android::hardware::security::secureclock::TimeStampToken;
67using ::aidl::android::security::authorization::AuthorizationTokens;
68using ::aidl::android::security::authorization::IKeystoreAuthorization;
69
David Zeuthena6f9fba2020-02-11 22:08:27 -050070Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
David Zeuthen472e6c82020-10-16 11:50:13 -040071 const std::string& credentialName, uid_t callingUid,
72 HardwareInformation hwInfo, sp<IIdentityCredentialStore> halStoreBinder,
David Zeuthen045a2c82021-09-11 13:52:17 -040073 sp<IPresentationSession> halSessionBinder, int halApiVersion)
David Zeuthen472e6c82020-10-16 11:50:13 -040074 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName),
75 callingUid_(callingUid), hwInfo_(std::move(hwInfo)), halStoreBinder_(halStoreBinder),
David Zeuthen045a2c82021-09-11 13:52:17 -040076 halSessionBinder_(halSessionBinder), halApiVersion_(halApiVersion) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040077
78Credential::~Credential() {}
79
David Zeuthen472e6c82020-10-16 11:50:13 -040080Status Credential::ensureOrReplaceHalBinder() {
81 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
David Zeuthenab3e5652019-10-28 13:32:48 -040082 if (!data->loadFromDisk()) {
83 LOG(ERROR) << "Error loading data for credential";
84 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
85 "Error loading data for credential");
86 }
87
David Zeuthen045a2c82021-09-11 13:52:17 -040088 // If we're in a session we explicitly don't get the binder to IIdentityCredential until
89 // it's used in getEntries() which is the only method call allowed for sessions.
90 //
91 // Why? This is because we want to throw the IIdentityCredential object away as soon as it's
92 // used because the HAL only guarantees a single IIdentityCredential object alive at a time
93 // and in a session there may be multiple credentials in play and we want to do multiple
94 // getEntries() calls on all of them.
95 //
96
97 if (!halSessionBinder_) {
98 sp<IIdentityCredential> halBinder;
99 Status status =
100 halStoreBinder_->getCredential(cipherSuite_, data->getCredentialData(), &halBinder);
101 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
102 int code = status.serviceSpecificErrorCode();
103 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
104 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
105 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500106 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400107 if (!status.isOk()) {
108 LOG(ERROR) << "Error getting HAL binder";
109 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
110 }
111 halBinder_ = halBinder;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500112 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400113
114 return Status::ok();
115}
116
117Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400118 if (halSessionBinder_) {
119 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
120 "Cannot be used with session");
121 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400122 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
123 if (!data->loadFromDisk()) {
124 LOG(ERROR) << "Error loading data for credential";
125 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
126 "Error loading data for credential");
127 }
128 *_aidl_return = data->getAttestationCertificate();
David Zeuthenab3e5652019-10-28 13:32:48 -0400129 return Status::ok();
130}
131
132// Returns operation handle
David Zeuthen472e6c82020-10-16 11:50:13 -0400133Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
David Zeuthen045a2c82021-09-11 13:52:17 -0400134 bool incrementUsageCount, int64_t* _aidl_return) {
135 if (halSessionBinder_) {
136 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
137 "Cannot be used with session");
138 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400139 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
140 if (!data->loadFromDisk()) {
141 LOG(ERROR) << "Error loading data for credential";
142 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
143 "Error loading data for credential");
144 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400145
David Zeuthen27407a52021-03-04 16:32:43 -0500146 // We just check if a key is available, we actually don't store it since we
147 // don't keep CredentialData around between binder calls.
148 const AuthKeyData* authKey =
David Zeuthen045a2c82021-09-11 13:52:17 -0400149 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys, incrementUsageCount);
David Zeuthen27407a52021-03-04 16:32:43 -0500150 if (authKey == nullptr) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400151 return Status::fromServiceSpecificError(
152 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
153 "No suitable authentication key available");
154 }
155
David Zeuthen27407a52021-03-04 16:32:43 -0500156 if (!ensureChallenge()) {
157 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
158 "Error getting challenge (bug in HAL or TA)");
159 }
160 *_aidl_return = selectedChallenge_;
161 return Status::ok();
162}
163
164bool Credential::ensureChallenge() {
165 if (selectedChallenge_ != 0) {
166 return true;
167 }
168
David Zeuthena6f9fba2020-02-11 22:08:27 -0500169 int64_t challenge;
David Zeuthen045a2c82021-09-11 13:52:17 -0400170 // If we're in a session, the challenge is selected by the session
171 if (halSessionBinder_) {
172 Status status = halSessionBinder_->getAuthChallenge(&challenge);
173 if (!status.isOk()) {
174 LOG(ERROR) << "Error getting challenge from session: " << status.exceptionMessage();
175 return false;
176 }
177 } else {
178 Status status = halBinder_->createAuthChallenge(&challenge);
179 if (!status.isOk()) {
180 LOG(ERROR) << "Error getting challenge: " << status.exceptionMessage();
181 return false;
182 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400183 }
184 if (challenge == 0) {
David Zeuthen27407a52021-03-04 16:32:43 -0500185 LOG(ERROR) << "Returned challenge is 0 (bug in HAL or TA)";
186 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400187 }
188
189 selectedChallenge_ = challenge;
David Zeuthen27407a52021-03-04 16:32:43 -0500190 return true;
David Zeuthenab3e5652019-10-28 13:32:48 -0400191}
192
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000193// Returns false if an error occurred communicating with keystore.
194//
195bool getTokensFromKeystore2(uint64_t challenge, uint64_t secureUserId,
196 unsigned int authTokenMaxAgeMillis,
197 AidlHardwareAuthToken& aidlAuthToken,
198 AidlVerificationToken& aidlVerificationToken) {
199 // try to connect to IKeystoreAuthorization AIDL service first.
200 AIBinder* authzAIBinder = AServiceManager_checkService("android.security.authorization");
201 ::ndk::SpAIBinder authzBinder(authzAIBinder);
202 auto authzService = IKeystoreAuthorization::fromBinder(authzBinder);
203 if (authzService) {
204 AuthorizationTokens authzTokens;
205 auto result = authzService->getAuthTokensForCredStore(challenge, secureUserId,
206 authTokenMaxAgeMillis, &authzTokens);
207 // Convert KeyMint auth token to KeyMaster authtoken, only if tokens are
208 // returned
209 if (result.isOk()) {
210 KeyMintAuthToken keymintAuthToken = authzTokens.authToken;
211 aidlAuthToken.challenge = keymintAuthToken.challenge;
212 aidlAuthToken.userId = keymintAuthToken.userId;
213 aidlAuthToken.authenticatorId = keymintAuthToken.authenticatorId;
214 aidlAuthToken.authenticatorType =
215 ::android::hardware::keymaster::HardwareAuthenticatorType(
216 int32_t(keymintAuthToken.authenticatorType));
217 aidlAuthToken.timestamp.milliSeconds = keymintAuthToken.timestamp.milliSeconds;
218 aidlAuthToken.mac = keymintAuthToken.mac;
219
220 // Convert timestamp token to KeyMaster verification token
221 TimeStampToken timestampToken = authzTokens.timestampToken;
222 aidlVerificationToken.challenge = timestampToken.challenge;
223 aidlVerificationToken.timestamp.milliSeconds = timestampToken.timestamp.milliSeconds;
224 // Legacy verification tokens were always minted by TEE.
225 aidlVerificationToken.securityLevel = SecurityLevel::TRUSTED_ENVIRONMENT;
226 aidlVerificationToken.mac = timestampToken.mac;
227 } else {
228 if (result.getServiceSpecificError() == 0) {
229 // Here we differentiate the errors occurred during communication
230 // from the service specific errors.
231 LOG(ERROR) << "Error getting tokens from keystore2: " << result.getDescription();
232 return false;
233 } else {
Hasini Gunasinghe984c6302021-03-15 16:10:57 +0000234 // Log the reason for not receiving auth tokens from keystore2.
235 LOG(INFO) << "Auth tokens were not received due to: " << result.getDescription();
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000236 }
237 }
238 return true;
239 } else {
240 LOG(ERROR) << "Error connecting to IKeystoreAuthorization service";
241 return false;
242 }
243}
244
David Zeuthenab3e5652019-10-28 13:32:48 -0400245Status Credential::getEntries(const vector<uint8_t>& requestMessage,
246 const vector<RequestNamespaceParcel>& requestNamespaces,
247 const vector<uint8_t>& sessionTranscript,
248 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
David Zeuthen045a2c82021-09-11 13:52:17 -0400249 bool allowUsingExpiredKeys, bool incrementUsageCount,
250 GetEntriesResultParcel* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400251 GetEntriesResultParcel ret;
252
David Zeuthen472e6c82020-10-16 11:50:13 -0400253 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
254 if (!data->loadFromDisk()) {
255 LOG(ERROR) << "Error loading data for credential";
256 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
257 "Error loading data for credential");
258 }
259
David Zeuthen045a2c82021-09-11 13:52:17 -0400260 // If used in a session, get the binder on demand...
261 //
262 sp<IIdentityCredential> halBinder = halBinder_;
263 if (halSessionBinder_) {
264 if (halBinder) {
265 LOG(ERROR) << "Unexpected HAL binder for session";
266 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
267 "Unexpected HAL binder for session");
268 }
269 Status status = halSessionBinder_->getCredential(data->getCredentialData(), &halBinder);
270 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
271 int code = status.serviceSpecificErrorCode();
272 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
273 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
274 }
275 }
276 if (!status.isOk()) {
277 LOG(ERROR) << "Error getting HAL binder";
278 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
279 }
280 }
281
David Zeuthenab3e5652019-10-28 13:32:48 -0400282 // Calculate requestCounts ahead of time and be careful not to include
283 // elements that don't exist.
284 //
285 // Also go through and figure out which access control profiles to include
286 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500287 vector<int32_t> requestCounts;
David Zeuthen472e6c82020-10-16 11:50:13 -0400288 const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
David Zeuthen52630002020-07-10 14:10:05 -0400289
290 // We don't support ACP identifiers which isn't in the range 0 to 31. This
291 // guarantee exists so it's feasible to implement the TA part of an Identity
292 // Credential HAL implementation where the TA uses a 32-bit word to indicate
293 // which profiles are authorized.
294 for (const SecureAccessControlProfile& profile : allProfiles) {
295 if (profile.id < 0 || profile.id >= 32) {
296 return Status::fromServiceSpecificError(
297 ICredentialStore::ERROR_GENERIC,
298 "Invalid accessProfileId in profile (must be between 0 and 31)");
299 }
300 }
301
302 vector<bool> includeProfile(32);
303
David Zeuthenab3e5652019-10-28 13:32:48 -0400304 for (const RequestNamespaceParcel& rns : requestNamespaces) {
305 size_t numEntriesInNsToRequest = 0;
306 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400307 if (data->hasEntryData(rns.namespaceName, rep.name)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400308 numEntriesInNsToRequest++;
309 }
310
David Zeuthen472e6c82020-10-16 11:50:13 -0400311 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
312 if (eData) {
313 for (int32_t id : eData.value().accessControlProfileIds) {
David Zeuthen52630002020-07-10 14:10:05 -0400314 if (id < 0 || id >= 32) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400315 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
316 << rns.namespaceName << ": " << rep.name;
317 return Status::fromServiceSpecificError(
David Zeuthen52630002020-07-10 14:10:05 -0400318 ICredentialStore::ERROR_GENERIC,
319 "Invalid accessProfileId in entry (must be between 0 and 31)");
David Zeuthenab3e5652019-10-28 13:32:48 -0400320 }
321 includeProfile[id] = true;
322 }
323 }
324 }
325 requestCounts.push_back(numEntriesInNsToRequest);
326 }
327
328 // Now that we know which profiles are needed, send only those to the
329 // HAL.
330 vector<SecureAccessControlProfile> selectedProfiles;
331 for (size_t n = 0; n < allProfiles.size(); n++) {
David Zeuthen52630002020-07-10 14:10:05 -0400332 if (includeProfile[allProfiles[n].id]) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400333 selectedProfiles.push_back(allProfiles[n]);
334 }
335 }
336
337 // Calculate the highest [1] non-zero timeout and if user-auth is needed
338 // ... we need this to select an appropriate authToken.
339 //
340 // [1] : Why do we request the highest timeout and not the lowest? Well, we
341 // return partial results in getEntries e.g. if some data elements
342 // fail to authorize we'll still return the ones that did not fail. So
343 // e.g. consider data elements A and B where A has an ACP with 60
344 // seconds and B has an ACP with 3600 seconds. In this case we'll be
345 // fine with getting an authToken for e.g. 2400 seconds which would
346 // mean returning only B.
347 //
348 bool userAuthNeeded = false;
349 unsigned int authTokenMaxAgeMillis = 0;
350 for (auto& profile : selectedProfiles) {
351 if (profile.userAuthenticationRequired) {
352 userAuthNeeded = true;
353 if (profile.timeoutMillis > 0) {
354 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
355 authTokenMaxAgeMillis = profile.timeoutMillis;
356 }
357 }
358 }
359 }
360
David Zeuthen59102f32020-05-08 10:58:09 -0400361 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
362 // is needed in any of the access control profiles for data items being requested.
363 //
David Zeuthena6f9fba2020-02-11 22:08:27 -0500364 AidlHardwareAuthToken aidlAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400365 AidlVerificationToken aidlVerificationToken;
366 aidlAuthToken.challenge = 0;
367 aidlAuthToken.userId = 0;
368 aidlAuthToken.authenticatorId = 0;
369 aidlAuthToken.authenticatorType =
370 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
371 aidlAuthToken.timestamp.milliSeconds = 0;
372 aidlAuthToken.mac.clear();
373 aidlVerificationToken.challenge = 0;
374 aidlVerificationToken.timestamp.milliSeconds = 0;
375 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
376 aidlVerificationToken.mac.clear();
David Zeuthenab3e5652019-10-28 13:32:48 -0400377 if (userAuthNeeded) {
David Zeuthen27407a52021-03-04 16:32:43 -0500378 // If user authentication is needed, always get a challenge from the
379 // HAL/TA since it'll need it to check the returned VerificationToken
380 // for freshness.
381 if (!ensureChallenge()) {
382 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
383 "Error getting challenge (bug in HAL or TA)");
384 }
385
386 // Note: if all selected profiles require auth-on-every-presentation
387 // then authTokenMaxAgeMillis will be 0 (because timeoutMillis for each
388 // profile is 0). Which means that keystore will only return an
389 // AuthToken if its challenge matches what we pass, regardless of its
390 // age. This is intended b/c the HAL/TA will check not care about
391 // the age in this case, it only cares that the challenge matches.
392 //
393 // Otherwise, if one or more of the profiles is auth-with-a-timeout then
394 // authTokenMaxAgeMillis will be set to the largest of those
395 // timeouts. We'll get an AuthToken which satisfies this deadline if it
396 // exists. This authToken _may_ have the requested challenge but it's
397 // not a guarantee and it's also not required.
398 //
399
Hasini Gunasinghe8c9853f2021-03-09 02:55:57 +0000400 if (!getTokensFromKeystore2(selectedChallenge_, data->getSecureUserId(),
401 authTokenMaxAgeMillis, aidlAuthToken, aidlVerificationToken)) {
402 LOG(ERROR) << "Error getting tokens from keystore2";
403 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
404 "Error getting tokens from keystore2");
David Zeuthen59102f32020-05-08 10:58:09 -0400405 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400406 }
407
David Zeuthen045a2c82021-09-11 13:52:17 -0400408 // Reuse the same AuthKey over multiple getEntries() calls.
David Zeuthen27407a52021-03-04 16:32:43 -0500409 //
David Zeuthen045a2c82021-09-11 13:52:17 -0400410 bool updateUseCountOnDisk = false;
411 if (!selectedAuthKey_) {
412 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
413 // the Java layer. So we could end up with no previously selected auth key and we may
414 // need one.
David Zeuthen27407a52021-03-04 16:32:43 -0500415 //
David Zeuthen045a2c82021-09-11 13:52:17 -0400416 const AuthKeyData* authKey = data->selectAuthKey(
417 allowUsingExhaustedKeys, allowUsingExpiredKeys, incrementUsageCount);
418 if (authKey == nullptr) {
419 // If no authKey is available, consider it an error only when a
420 // SessionTranscript was provided.
421 //
422 // We allow no SessionTranscript to be provided because it makes
423 // the API simpler to deal with insofar it can be used without having
424 // to generate any authentication keys.
425 //
426 // In this "no SessionTranscript is provided" mode we don't return
427 // DeviceNameSpaces nor a MAC over DeviceAuthentication so we don't
428 // need a device key.
429 //
430 if (sessionTranscript.size() > 0) {
431 return Status::fromServiceSpecificError(
432 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
433 "No suitable authentication key available and one is needed");
434 }
435 } else {
436 // We did find an authKey. Store its contents for future getEntries() calls.
437 updateUseCountOnDisk = true;
438 selectedAuthKeySigningKeyBlob_ = authKey->keyBlob;
439 selectedAuthKeyStaticAuthData_ = authKey->staticAuthenticationData;
David Zeuthen55975ec2020-02-27 14:28:18 -0500440 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400441 selectedAuthKey_ = true;
David Zeuthen55975ec2020-02-27 14:28:18 -0500442 }
443
David Zeuthene2a78a42020-04-27 13:34:38 -0400444 // Pass the HAL enough information to allow calculating the size of
445 // DeviceNameSpaces ahead of time.
446 vector<RequestNamespace> halRequestNamespaces;
447 for (const RequestNamespaceParcel& rns : requestNamespaces) {
448 RequestNamespace ns;
449 ns.namespaceName = rns.namespaceName;
450 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400451 optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
David Zeuthene2a78a42020-04-27 13:34:38 -0400452 if (entryData) {
453 RequestDataItem di;
454 di.name = rep.name;
455 di.size = entryData.value().size;
456 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
457 ns.items.push_back(di);
458 }
459 }
460 if (ns.items.size() > 0) {
461 halRequestNamespaces.push_back(ns);
462 }
463 }
464 // This is not catastrophic, we might be dealing with a version 1 implementation which
465 // doesn't have this method.
David Zeuthen045a2c82021-09-11 13:52:17 -0400466 Status status = halBinder->setRequestedNamespaces(halRequestNamespaces);
David Zeuthene2a78a42020-04-27 13:34:38 -0400467 if (!status.isOk()) {
David Zeuthen59102f32020-05-08 10:58:09 -0400468 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
469 << "and continuing";
470 }
471
472 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
David Zeuthen045a2c82021-09-11 13:52:17 -0400473 status = halBinder->setVerificationToken(aidlVerificationToken);
David Zeuthen59102f32020-05-08 10:58:09 -0400474 if (!status.isOk()) {
475 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
David Zeuthene2a78a42020-04-27 13:34:38 -0400476 << "and continuing";
477 }
478
David Zeuthen045a2c82021-09-11 13:52:17 -0400479 status = halBinder->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage,
480 selectedAuthKeySigningKeyBlob_, sessionTranscript,
481 readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500482 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
483 int code = status.serviceSpecificErrorCode();
484 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
485 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
486 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
487 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
488 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
489 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
490 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
491 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
492 }
493 }
494 if (!status.isOk()) {
495 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400496 }
497
498 for (const RequestNamespaceParcel& rns : requestNamespaces) {
499 ResultNamespaceParcel resultNamespaceParcel;
500 resultNamespaceParcel.namespaceName = rns.namespaceName;
501
502 for (const RequestEntryParcel& rep : rns.entries) {
503 ResultEntryParcel resultEntryParcel;
504 resultEntryParcel.name = rep.name;
505
David Zeuthen472e6c82020-10-16 11:50:13 -0400506 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
507 if (!eData) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400508 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
509 resultNamespaceParcel.entries.push_back(resultEntryParcel);
510 continue;
511 }
512
David Zeuthena6f9fba2020-02-11 22:08:27 -0500513 status =
David Zeuthen045a2c82021-09-11 13:52:17 -0400514 halBinder->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
515 eData.value().accessControlProfileIds);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500516 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
517 int code = status.serviceSpecificErrorCode();
518 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
519 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
520 resultNamespaceParcel.entries.push_back(resultEntryParcel);
521 continue;
522 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
523 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
524 resultNamespaceParcel.entries.push_back(resultEntryParcel);
525 continue;
526 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
527 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
528 resultNamespaceParcel.entries.push_back(resultEntryParcel);
529 continue;
530 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
531 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
532 resultNamespaceParcel.entries.push_back(resultEntryParcel);
533 continue;
534 }
535 }
536 if (!status.isOk()) {
537 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400538 }
539
540 vector<uint8_t> value;
David Zeuthen472e6c82020-10-16 11:50:13 -0400541 for (const auto& encryptedChunk : eData.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500542 vector<uint8_t> chunk;
David Zeuthen045a2c82021-09-11 13:52:17 -0400543 status = halBinder->retrieveEntryValue(encryptedChunk, &chunk);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500544 if (!status.isOk()) {
545 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400546 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500547 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400548 }
549
550 resultEntryParcel.status = STATUS_OK;
551 resultEntryParcel.value = value;
552 resultNamespaceParcel.entries.push_back(resultEntryParcel);
553 }
554 ret.resultNamespaces.push_back(resultNamespaceParcel);
555 }
556
David Zeuthenfdf7f522022-10-05 13:21:05 -0400557 // API version 5 (feature version 202301) supports both MAC and ECDSA signature.
558 if (halApiVersion_ >= 5) {
559 status = halBinder->finishRetrievalWithSignature(&ret.mac, &ret.deviceNameSpaces,
560 &ret.signature);
561 if (!status.isOk()) {
562 return halStatusToGenericError(status);
563 }
564 } else {
565 status = halBinder->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
566 if (!status.isOk()) {
567 return halStatusToGenericError(status);
568 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500569 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400570 ret.staticAuthenticationData = selectedAuthKeyStaticAuthData_;
David Zeuthenab3e5652019-10-28 13:32:48 -0400571
572 // Ensure useCount is updated on disk.
David Zeuthen045a2c82021-09-11 13:52:17 -0400573 if (updateUseCountOnDisk) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400574 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400575 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
576 "Error saving data");
577 }
578 }
579
580 *_aidl_return = ret;
581 return Status::ok();
582}
583
584Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400585 if (halSessionBinder_) {
586 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
587 "Cannot be used with session");
588 }
589
David Zeuthena6f9fba2020-02-11 22:08:27 -0500590 vector<uint8_t> proofOfDeletionSignature;
David Zeuthen472e6c82020-10-16 11:50:13 -0400591
592 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
593 if (!data->loadFromDisk()) {
594 LOG(ERROR) << "Error loading data for credential";
595 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
596 "Error loading data for credential");
597 }
598
David Zeuthena6f9fba2020-02-11 22:08:27 -0500599 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
600 if (!status.isOk()) {
601 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400602 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400603 if (!data->deleteCredential()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400604 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
605 "Error deleting credential data on disk");
606 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500607 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400608 return Status::ok();
609}
610
David Zeuthen472e6c82020-10-16 11:50:13 -0400611Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
612 vector<uint8_t>* _aidl_return) {
613 if (halApiVersion_ < 3) {
614 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
615 "Not implemented by HAL");
616 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400617
618 if (halSessionBinder_) {
619 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
620 "Cannot be used with session");
621 }
622
David Zeuthen472e6c82020-10-16 11:50:13 -0400623 vector<uint8_t> proofOfDeletionSignature;
624
625 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
626 if (!data->loadFromDisk()) {
627 LOG(ERROR) << "Error loading data for credential";
628 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
629 "Error loading data for credential");
630 }
631
632 Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
633 if (!status.isOk()) {
634 return halStatusToGenericError(status);
635 }
636 if (!data->deleteCredential()) {
637 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
638 "Error deleting credential data on disk");
639 }
640 *_aidl_return = proofOfDeletionSignature;
641 return Status::ok();
642}
643
644Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
645 if (halApiVersion_ < 3) {
646 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
647 "Not implemented by HAL");
648 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400649
650 if (halSessionBinder_) {
651 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
652 "Cannot be used with session");
653 }
654
David Zeuthen472e6c82020-10-16 11:50:13 -0400655 vector<uint8_t> proofOfOwnershipSignature;
656 Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
657 if (!status.isOk()) {
658 return halStatusToGenericError(status);
659 }
660 *_aidl_return = proofOfOwnershipSignature;
661 return Status::ok();
662}
663
David Zeuthenab3e5652019-10-28 13:32:48 -0400664Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400665 if (halSessionBinder_) {
666 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
667 "Cannot be used with session");
668 }
669
David Zeuthenab3e5652019-10-28 13:32:48 -0400670 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500671 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
672 if (!status.isOk()) {
673 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400674 }
675
David Zeuthen045a2c82021-09-11 13:52:17 -0400676 time_t nowSeconds = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
677 time_t validityNotBefore = nowSeconds;
678 time_t validityNotAfter = nowSeconds + 24 * 60 * 60;
David Zeuthenab3e5652019-10-28 13:32:48 -0400679 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
680 "ephemeralKey", // Alias for key
681 "0", // Serial, as a decimal number
682 "Credstore", // Issuer
683 "Ephemeral Key", // Subject
David Zeuthen045a2c82021-09-11 13:52:17 -0400684 validityNotBefore, validityNotAfter);
David Zeuthenab3e5652019-10-28 13:32:48 -0400685 if (!pkcs12Bytes) {
686 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
687 "Error creating PKCS#12 structure for key pair");
688 }
689 *_aidl_return = pkcs12Bytes.value();
690 return Status::ok();
691}
692
693Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400694 if (halSessionBinder_) {
695 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
696 "Cannot be used with session");
697 }
698
David Zeuthena6f9fba2020-02-11 22:08:27 -0500699 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
700 if (!status.isOk()) {
701 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400702 }
703 return Status::ok();
704}
705
706Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400707 if (halSessionBinder_) {
708 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
709 "Cannot be used with session");
710 }
711
David Zeuthen472e6c82020-10-16 11:50:13 -0400712 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
713 if (!data->loadFromDisk()) {
714 LOG(ERROR) << "Error loading data for credential";
715 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
716 "Error loading data for credential");
717 }
718 data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
719 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400720 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
721 "Error saving data");
722 }
723 return Status::ok();
724}
725
726Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400727 if (halSessionBinder_) {
728 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
729 "Cannot be used with session");
730 }
731
David Zeuthen472e6c82020-10-16 11:50:13 -0400732 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
733 if (!data->loadFromDisk()) {
734 LOG(ERROR) << "Error loading data for credential";
735 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
736 "Error loading data for credential");
737 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400738 optional<vector<vector<uint8_t>>> keysNeedingCert =
David Zeuthen472e6c82020-10-16 11:50:13 -0400739 data->getAuthKeysNeedingCertification(halBinder_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400740 if (!keysNeedingCert) {
741 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
742 "Error getting auth keys neededing certification");
743 }
744 vector<AuthKeyParcel> authKeyParcels;
745 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
746 AuthKeyParcel authKeyParcel;
747 authKeyParcel.x509cert = key;
748 authKeyParcels.push_back(authKeyParcel);
749 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400750 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400751 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
752 "Error saving data");
753 }
754 *_aidl_return = authKeyParcels;
755 return Status::ok();
756}
757
758Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
759 const vector<uint8_t>& staticAuthData) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400760 if (halSessionBinder_) {
761 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
762 "Cannot be used with session");
763 }
764
David Zeuthen472e6c82020-10-16 11:50:13 -0400765 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
766 if (!data->loadFromDisk()) {
767 LOG(ERROR) << "Error loading data for credential";
768 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
769 "Error loading data for credential");
770 }
771 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
772 std::numeric_limits<int64_t>::max(), staticAuthData)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400773 return Status::fromServiceSpecificError(
774 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
775 "Error finding authentication key to store static "
776 "authentication data for");
777 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400778 if (!data->saveToDisk()) {
779 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
780 "Error saving data");
781 }
782 return Status::ok();
783}
784
785Status
786Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
787 int64_t expirationDateMillisSinceEpoch,
788 const vector<uint8_t>& staticAuthData) {
789 if (halApiVersion_ < 3) {
790 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
791 "Not implemented by HAL");
792 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400793
794 if (halSessionBinder_) {
795 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
796 "Cannot be used with session");
797 }
798
David Zeuthen472e6c82020-10-16 11:50:13 -0400799 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
800 if (!data->loadFromDisk()) {
801 LOG(ERROR) << "Error loading data for credential";
802 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
803 "Error loading data for credential");
804 }
805 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
806 expirationDateMillisSinceEpoch, staticAuthData)) {
807 return Status::fromServiceSpecificError(
808 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
809 "Error finding authentication key to store static "
810 "authentication data for");
811 }
812 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400813 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
814 "Error saving data");
815 }
816 return Status::ok();
817}
818
819Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
David Zeuthen045a2c82021-09-11 13:52:17 -0400820 if (halSessionBinder_) {
821 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
822 "Cannot be used with session");
823 }
824
David Zeuthen472e6c82020-10-16 11:50:13 -0400825 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
826 if (!data->loadFromDisk()) {
827 LOG(ERROR) << "Error loading data for credential";
828 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
829 "Error loading data for credential");
830 }
831 const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
David Zeuthenab3e5652019-10-28 13:32:48 -0400832 vector<int32_t> ret;
833 for (const AuthKeyData& authKeyData : authKeyDatas) {
834 ret.push_back(authKeyData.useCount);
835 }
836 *_aidl_return = ret;
837 return Status::ok();
838}
839
David Zeuthen472e6c82020-10-16 11:50:13 -0400840optional<string> extractDocType(const vector<uint8_t>& credentialData) {
841 auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
842 if (item == nullptr) {
843 LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
844 return {};
845 }
846 const cppbor::Array* array = item->asArray();
847 if (array == nullptr || array->size() < 1) {
848 LOG(ERROR) << "CredentialData array with at least one element";
849 return {};
850 }
851 const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
852 if (tstr == nullptr) {
853 LOG(ERROR) << "First item in CredentialData is not a string";
854 return {};
855 }
856 return tstr->value();
857}
858
859Status Credential::update(sp<IWritableCredential>* _aidl_return) {
860 if (halApiVersion_ < 3) {
861 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
862 "Not implemented by HAL");
863 }
David Zeuthen045a2c82021-09-11 13:52:17 -0400864
865 if (halSessionBinder_) {
866 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
867 "Cannot be used with session");
868 }
869
David Zeuthen472e6c82020-10-16 11:50:13 -0400870 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
871 if (!data->loadFromDisk()) {
872 LOG(ERROR) << "Error loading data for credential";
873 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
874 "Error loading data for credential");
875 }
876
877 sp<IWritableIdentityCredential> halWritableCredential;
878 Status status = halBinder_->updateCredential(&halWritableCredential);
879 if (!status.isOk()) {
880 return halStatusToGenericError(status);
881 }
882
883 optional<string> docType = extractDocType(data->getCredentialData());
884 if (!docType) {
885 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
886 "Unable to extract DocType from CredentialData");
887 }
888
889 // NOTE: The caller is expected to call WritableCredential::personalize() which will
890 // write brand new data to disk, specifically it will overwrite any data already
891 // have _including_ authentication keys.
892 //
893 // It is because of this we need to set the CredentialKey certificate chain,
894 // keyCount, and maxUsesPerKey below.
David Zeuthen27407a52021-03-04 16:32:43 -0500895 sp<WritableCredential> writableCredential = new WritableCredential(
896 dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
David Zeuthen472e6c82020-10-16 11:50:13 -0400897
898 writableCredential->setAttestationCertificate(data->getAttestationCertificate());
899 auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
900 writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
901
David Zeuthen27407a52021-03-04 16:32:43 -0500902 // Because its data has changed, we need to replace the binder for the
903 // IIdentityCredential when the credential has been updated... otherwise the
904 // remote object will have stale data for future calls, for example
905 // getAuthKeysNeedingCertification().
David Zeuthen472e6c82020-10-16 11:50:13 -0400906 //
David Zeuthen27407a52021-03-04 16:32:43 -0500907 // The way this is implemented is that setCredentialToReloadWhenUpdated()
908 // instructs the WritableCredential to call writableCredentialPersonalized()
909 // on |this|.
David Zeuthen472e6c82020-10-16 11:50:13 -0400910 //
David Zeuthen27407a52021-03-04 16:32:43 -0500911 //
912 writableCredential->setCredentialToReloadWhenUpdated(this);
David Zeuthen472e6c82020-10-16 11:50:13 -0400913
914 *_aidl_return = writableCredential;
915 return Status::ok();
916}
917
David Zeuthen27407a52021-03-04 16:32:43 -0500918void Credential::writableCredentialPersonalized() {
919 Status status = ensureOrReplaceHalBinder();
920 if (!status.isOk()) {
921 LOG(ERROR) << "Error reloading credential";
922 }
923}
924
David Zeuthenab3e5652019-10-28 13:32:48 -0400925} // namespace identity
926} // namespace security
927} // namespace android