blob: 7c75d8a2411c9642a350e4fa0278c7e1d1d65628 [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,
73 int halApiVersion)
74 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName),
75 callingUid_(callingUid), hwInfo_(std::move(hwInfo)), halStoreBinder_(halStoreBinder),
76 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 Zeuthenab3e5652019-10-28 13:32:48 -040088 sp<IIdentityCredential> halBinder;
David Zeuthena6f9fba2020-02-11 22:08:27 -050089 Status status =
David Zeuthen472e6c82020-10-16 11:50:13 -040090 halStoreBinder_->getCredential(cipherSuite_, data->getCredentialData(), &halBinder);
David Zeuthena6f9fba2020-02-11 22:08:27 -050091 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
92 int code = status.serviceSpecificErrorCode();
93 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
94 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
95 }
96 }
97 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -040098 LOG(ERROR) << "Error getting HAL binder";
99 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
100 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400101 halBinder_ = halBinder;
102
103 return Status::ok();
104}
105
106Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400107 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
108 if (!data->loadFromDisk()) {
109 LOG(ERROR) << "Error loading data for credential";
110 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
111 "Error loading data for credential");
112 }
113 *_aidl_return = data->getAttestationCertificate();
David Zeuthenab3e5652019-10-28 13:32:48 -0400114 return Status::ok();
115}
116
117// Returns operation handle
David Zeuthen472e6c82020-10-16 11:50:13 -0400118Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
119 int64_t* _aidl_return) {
120 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
121 if (!data->loadFromDisk()) {
122 LOG(ERROR) << "Error loading data for credential";
123 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
124 "Error loading data for credential");
125 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400126
David Zeuthen27407a52021-03-04 16:32:43 -0500127 // We just check if a key is available, we actually don't store it since we
128 // don't keep CredentialData around between binder calls.
129 const AuthKeyData* authKey =
130 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
131 if (authKey == nullptr) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400132 return Status::fromServiceSpecificError(
133 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
134 "No suitable authentication key available");
135 }
136
David Zeuthen27407a52021-03-04 16:32:43 -0500137 if (!ensureChallenge()) {
138 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
139 "Error getting challenge (bug in HAL or TA)");
140 }
141 *_aidl_return = selectedChallenge_;
142 return Status::ok();
143}
144
145bool Credential::ensureChallenge() {
146 if (selectedChallenge_ != 0) {
147 return true;
148 }
149
David Zeuthena6f9fba2020-02-11 22:08:27 -0500150 int64_t challenge;
151 Status status = halBinder_->createAuthChallenge(&challenge);
152 if (!status.isOk()) {
David Zeuthen27407a52021-03-04 16:32:43 -0500153 LOG(ERROR) << "Error getting challenge: " << status.exceptionMessage();
154 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400155 }
156 if (challenge == 0) {
David Zeuthen27407a52021-03-04 16:32:43 -0500157 LOG(ERROR) << "Returned challenge is 0 (bug in HAL or TA)";
158 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400159 }
160
161 selectedChallenge_ = challenge;
David Zeuthen27407a52021-03-04 16:32:43 -0500162 return true;
David Zeuthenab3e5652019-10-28 13:32:48 -0400163}
164
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000165// Returns false if an error occurred communicating with keystore.
166//
167bool getTokensFromKeystore2(uint64_t challenge, uint64_t secureUserId,
168 unsigned int authTokenMaxAgeMillis,
169 AidlHardwareAuthToken& aidlAuthToken,
170 AidlVerificationToken& aidlVerificationToken) {
171 // try to connect to IKeystoreAuthorization AIDL service first.
172 AIBinder* authzAIBinder = AServiceManager_checkService("android.security.authorization");
173 ::ndk::SpAIBinder authzBinder(authzAIBinder);
174 auto authzService = IKeystoreAuthorization::fromBinder(authzBinder);
175 if (authzService) {
176 AuthorizationTokens authzTokens;
177 auto result = authzService->getAuthTokensForCredStore(challenge, secureUserId,
178 authTokenMaxAgeMillis, &authzTokens);
179 // Convert KeyMint auth token to KeyMaster authtoken, only if tokens are
180 // returned
181 if (result.isOk()) {
182 KeyMintAuthToken keymintAuthToken = authzTokens.authToken;
183 aidlAuthToken.challenge = keymintAuthToken.challenge;
184 aidlAuthToken.userId = keymintAuthToken.userId;
185 aidlAuthToken.authenticatorId = keymintAuthToken.authenticatorId;
186 aidlAuthToken.authenticatorType =
187 ::android::hardware::keymaster::HardwareAuthenticatorType(
188 int32_t(keymintAuthToken.authenticatorType));
189 aidlAuthToken.timestamp.milliSeconds = keymintAuthToken.timestamp.milliSeconds;
190 aidlAuthToken.mac = keymintAuthToken.mac;
191
192 // Convert timestamp token to KeyMaster verification token
193 TimeStampToken timestampToken = authzTokens.timestampToken;
194 aidlVerificationToken.challenge = timestampToken.challenge;
195 aidlVerificationToken.timestamp.milliSeconds = timestampToken.timestamp.milliSeconds;
196 // Legacy verification tokens were always minted by TEE.
197 aidlVerificationToken.securityLevel = SecurityLevel::TRUSTED_ENVIRONMENT;
198 aidlVerificationToken.mac = timestampToken.mac;
199 } else {
200 if (result.getServiceSpecificError() == 0) {
201 // Here we differentiate the errors occurred during communication
202 // from the service specific errors.
203 LOG(ERROR) << "Error getting tokens from keystore2: " << result.getDescription();
204 return false;
205 } else {
Hasini Gunasinghe984c6302021-03-15 16:10:57 +0000206 // Log the reason for not receiving auth tokens from keystore2.
207 LOG(INFO) << "Auth tokens were not received due to: " << result.getDescription();
Hasini Gunasinghe1b531b92021-03-02 00:34:58 +0000208 }
209 }
210 return true;
211 } else {
212 LOG(ERROR) << "Error connecting to IKeystoreAuthorization service";
213 return false;
214 }
215}
216
David Zeuthenab3e5652019-10-28 13:32:48 -0400217Status Credential::getEntries(const vector<uint8_t>& requestMessage,
218 const vector<RequestNamespaceParcel>& requestNamespaces,
219 const vector<uint8_t>& sessionTranscript,
220 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
David Zeuthen472e6c82020-10-16 11:50:13 -0400221 bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400222 GetEntriesResultParcel ret;
223
David Zeuthen472e6c82020-10-16 11:50:13 -0400224 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
225 if (!data->loadFromDisk()) {
226 LOG(ERROR) << "Error loading data for credential";
227 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
228 "Error loading data for credential");
229 }
230
David Zeuthenab3e5652019-10-28 13:32:48 -0400231 // Calculate requestCounts ahead of time and be careful not to include
232 // elements that don't exist.
233 //
234 // Also go through and figure out which access control profiles to include
235 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500236 vector<int32_t> requestCounts;
David Zeuthen472e6c82020-10-16 11:50:13 -0400237 const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
David Zeuthen52630002020-07-10 14:10:05 -0400238
239 // We don't support ACP identifiers which isn't in the range 0 to 31. This
240 // guarantee exists so it's feasible to implement the TA part of an Identity
241 // Credential HAL implementation where the TA uses a 32-bit word to indicate
242 // which profiles are authorized.
243 for (const SecureAccessControlProfile& profile : allProfiles) {
244 if (profile.id < 0 || profile.id >= 32) {
245 return Status::fromServiceSpecificError(
246 ICredentialStore::ERROR_GENERIC,
247 "Invalid accessProfileId in profile (must be between 0 and 31)");
248 }
249 }
250
251 vector<bool> includeProfile(32);
252
David Zeuthenab3e5652019-10-28 13:32:48 -0400253 for (const RequestNamespaceParcel& rns : requestNamespaces) {
254 size_t numEntriesInNsToRequest = 0;
255 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400256 if (data->hasEntryData(rns.namespaceName, rep.name)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400257 numEntriesInNsToRequest++;
258 }
259
David Zeuthen472e6c82020-10-16 11:50:13 -0400260 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
261 if (eData) {
262 for (int32_t id : eData.value().accessControlProfileIds) {
David Zeuthen52630002020-07-10 14:10:05 -0400263 if (id < 0 || id >= 32) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400264 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
265 << rns.namespaceName << ": " << rep.name;
266 return Status::fromServiceSpecificError(
David Zeuthen52630002020-07-10 14:10:05 -0400267 ICredentialStore::ERROR_GENERIC,
268 "Invalid accessProfileId in entry (must be between 0 and 31)");
David Zeuthenab3e5652019-10-28 13:32:48 -0400269 }
270 includeProfile[id] = true;
271 }
272 }
273 }
274 requestCounts.push_back(numEntriesInNsToRequest);
275 }
276
277 // Now that we know which profiles are needed, send only those to the
278 // HAL.
279 vector<SecureAccessControlProfile> selectedProfiles;
280 for (size_t n = 0; n < allProfiles.size(); n++) {
David Zeuthen52630002020-07-10 14:10:05 -0400281 if (includeProfile[allProfiles[n].id]) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400282 selectedProfiles.push_back(allProfiles[n]);
283 }
284 }
285
286 // Calculate the highest [1] non-zero timeout and if user-auth is needed
287 // ... we need this to select an appropriate authToken.
288 //
289 // [1] : Why do we request the highest timeout and not the lowest? Well, we
290 // return partial results in getEntries e.g. if some data elements
291 // fail to authorize we'll still return the ones that did not fail. So
292 // e.g. consider data elements A and B where A has an ACP with 60
293 // seconds and B has an ACP with 3600 seconds. In this case we'll be
294 // fine with getting an authToken for e.g. 2400 seconds which would
295 // mean returning only B.
296 //
297 bool userAuthNeeded = false;
298 unsigned int authTokenMaxAgeMillis = 0;
299 for (auto& profile : selectedProfiles) {
300 if (profile.userAuthenticationRequired) {
301 userAuthNeeded = true;
302 if (profile.timeoutMillis > 0) {
303 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
304 authTokenMaxAgeMillis = profile.timeoutMillis;
305 }
306 }
307 }
308 }
309
David Zeuthen59102f32020-05-08 10:58:09 -0400310 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
311 // is needed in any of the access control profiles for data items being requested.
312 //
David Zeuthena6f9fba2020-02-11 22:08:27 -0500313 AidlHardwareAuthToken aidlAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400314 AidlVerificationToken aidlVerificationToken;
315 aidlAuthToken.challenge = 0;
316 aidlAuthToken.userId = 0;
317 aidlAuthToken.authenticatorId = 0;
318 aidlAuthToken.authenticatorType =
319 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
320 aidlAuthToken.timestamp.milliSeconds = 0;
321 aidlAuthToken.mac.clear();
322 aidlVerificationToken.challenge = 0;
323 aidlVerificationToken.timestamp.milliSeconds = 0;
324 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
325 aidlVerificationToken.mac.clear();
David Zeuthenab3e5652019-10-28 13:32:48 -0400326 if (userAuthNeeded) {
David Zeuthen27407a52021-03-04 16:32:43 -0500327 // If user authentication is needed, always get a challenge from the
328 // HAL/TA since it'll need it to check the returned VerificationToken
329 // for freshness.
330 if (!ensureChallenge()) {
331 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
332 "Error getting challenge (bug in HAL or TA)");
333 }
334
335 // Note: if all selected profiles require auth-on-every-presentation
336 // then authTokenMaxAgeMillis will be 0 (because timeoutMillis for each
337 // profile is 0). Which means that keystore will only return an
338 // AuthToken if its challenge matches what we pass, regardless of its
339 // age. This is intended b/c the HAL/TA will check not care about
340 // the age in this case, it only cares that the challenge matches.
341 //
342 // Otherwise, if one or more of the profiles is auth-with-a-timeout then
343 // authTokenMaxAgeMillis will be set to the largest of those
344 // timeouts. We'll get an AuthToken which satisfies this deadline if it
345 // exists. This authToken _may_ have the requested challenge but it's
346 // not a guarantee and it's also not required.
347 //
348
Hasini Gunasinghe8c9853f2021-03-09 02:55:57 +0000349 if (!getTokensFromKeystore2(selectedChallenge_, data->getSecureUserId(),
350 authTokenMaxAgeMillis, aidlAuthToken, aidlVerificationToken)) {
351 LOG(ERROR) << "Error getting tokens from keystore2";
352 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
353 "Error getting tokens from keystore2");
David Zeuthen59102f32020-05-08 10:58:09 -0400354 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400355 }
356
David Zeuthen55975ec2020-02-27 14:28:18 -0500357 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
358 // the Java layer. So we could end up with no previously selected auth key and we may
359 // need one.
David Zeuthen27407a52021-03-04 16:32:43 -0500360 //
361 const AuthKeyData* authKey =
362 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
363 if (authKey == nullptr) {
364 // If no authKey is available, consider it an error only when a
365 // SessionTranscript was provided.
366 //
367 // We allow no SessionTranscript to be provided because it makes
368 // the API simpler to deal with insofar it can be used without having
369 // to generate any authentication keys.
370 //
371 // In this "no SessionTranscript is provided" mode we don't return
372 // DeviceNameSpaces nor a MAC over DeviceAuthentication so we don't
373 // need a device key.
374 //
375 if (sessionTranscript.size() > 0) {
376 return Status::fromServiceSpecificError(
377 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
378 "No suitable authentication key available and one is needed");
David Zeuthen55975ec2020-02-27 14:28:18 -0500379 }
380 }
381 vector<uint8_t> signingKeyBlob;
382 if (authKey != nullptr) {
383 signingKeyBlob = authKey->keyBlob;
384 }
385
David Zeuthene2a78a42020-04-27 13:34:38 -0400386 // Pass the HAL enough information to allow calculating the size of
387 // DeviceNameSpaces ahead of time.
388 vector<RequestNamespace> halRequestNamespaces;
389 for (const RequestNamespaceParcel& rns : requestNamespaces) {
390 RequestNamespace ns;
391 ns.namespaceName = rns.namespaceName;
392 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400393 optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
David Zeuthene2a78a42020-04-27 13:34:38 -0400394 if (entryData) {
395 RequestDataItem di;
396 di.name = rep.name;
397 di.size = entryData.value().size;
398 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
399 ns.items.push_back(di);
400 }
401 }
402 if (ns.items.size() > 0) {
403 halRequestNamespaces.push_back(ns);
404 }
405 }
406 // This is not catastrophic, we might be dealing with a version 1 implementation which
407 // doesn't have this method.
408 Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces);
409 if (!status.isOk()) {
David Zeuthen59102f32020-05-08 10:58:09 -0400410 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
411 << "and continuing";
412 }
413
414 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
415 status = halBinder_->setVerificationToken(aidlVerificationToken);
416 if (!status.isOk()) {
417 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
David Zeuthene2a78a42020-04-27 13:34:38 -0400418 << "and continuing";
419 }
420
421 status =
David Zeuthen55975ec2020-02-27 14:28:18 -0500422 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
423 sessionTranscript, readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500424 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
425 int code = status.serviceSpecificErrorCode();
426 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
427 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
428 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
429 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
430 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
431 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
432 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
433 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
434 }
435 }
436 if (!status.isOk()) {
437 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400438 }
439
440 for (const RequestNamespaceParcel& rns : requestNamespaces) {
441 ResultNamespaceParcel resultNamespaceParcel;
442 resultNamespaceParcel.namespaceName = rns.namespaceName;
443
444 for (const RequestEntryParcel& rep : rns.entries) {
445 ResultEntryParcel resultEntryParcel;
446 resultEntryParcel.name = rep.name;
447
David Zeuthen472e6c82020-10-16 11:50:13 -0400448 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
449 if (!eData) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400450 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
451 resultNamespaceParcel.entries.push_back(resultEntryParcel);
452 continue;
453 }
454
David Zeuthena6f9fba2020-02-11 22:08:27 -0500455 status =
David Zeuthen472e6c82020-10-16 11:50:13 -0400456 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
457 eData.value().accessControlProfileIds);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500458 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
459 int code = status.serviceSpecificErrorCode();
460 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
461 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
462 resultNamespaceParcel.entries.push_back(resultEntryParcel);
463 continue;
464 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
465 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
466 resultNamespaceParcel.entries.push_back(resultEntryParcel);
467 continue;
468 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
469 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
470 resultNamespaceParcel.entries.push_back(resultEntryParcel);
471 continue;
472 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
473 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
474 resultNamespaceParcel.entries.push_back(resultEntryParcel);
475 continue;
476 }
477 }
478 if (!status.isOk()) {
479 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400480 }
481
482 vector<uint8_t> value;
David Zeuthen472e6c82020-10-16 11:50:13 -0400483 for (const auto& encryptedChunk : eData.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500484 vector<uint8_t> chunk;
485 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
486 if (!status.isOk()) {
487 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400488 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500489 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400490 }
491
492 resultEntryParcel.status = STATUS_OK;
493 resultEntryParcel.value = value;
494 resultNamespaceParcel.entries.push_back(resultEntryParcel);
495 }
496 ret.resultNamespaces.push_back(resultNamespaceParcel);
497 }
498
David Zeuthen55975ec2020-02-27 14:28:18 -0500499 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500500 if (!status.isOk()) {
501 return halStatusToGenericError(status);
502 }
503 if (authKey != nullptr) {
504 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400505 }
506
507 // Ensure useCount is updated on disk.
508 if (authKey != nullptr) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400509 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400510 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
511 "Error saving data");
512 }
513 }
514
515 *_aidl_return = ret;
516 return Status::ok();
517}
518
519Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500520 vector<uint8_t> proofOfDeletionSignature;
David Zeuthen472e6c82020-10-16 11:50:13 -0400521
522 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
523 if (!data->loadFromDisk()) {
524 LOG(ERROR) << "Error loading data for credential";
525 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
526 "Error loading data for credential");
527 }
528
David Zeuthena6f9fba2020-02-11 22:08:27 -0500529 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
530 if (!status.isOk()) {
531 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400532 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400533 if (!data->deleteCredential()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400534 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
535 "Error deleting credential data on disk");
536 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500537 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400538 return Status::ok();
539}
540
David Zeuthen472e6c82020-10-16 11:50:13 -0400541Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
542 vector<uint8_t>* _aidl_return) {
543 if (halApiVersion_ < 3) {
544 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
545 "Not implemented by HAL");
546 }
547 vector<uint8_t> proofOfDeletionSignature;
548
549 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
550 if (!data->loadFromDisk()) {
551 LOG(ERROR) << "Error loading data for credential";
552 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
553 "Error loading data for credential");
554 }
555
556 Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
557 if (!status.isOk()) {
558 return halStatusToGenericError(status);
559 }
560 if (!data->deleteCredential()) {
561 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
562 "Error deleting credential data on disk");
563 }
564 *_aidl_return = proofOfDeletionSignature;
565 return Status::ok();
566}
567
568Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
569 if (halApiVersion_ < 3) {
570 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
571 "Not implemented by HAL");
572 }
573 vector<uint8_t> proofOfOwnershipSignature;
574 Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
575 if (!status.isOk()) {
576 return halStatusToGenericError(status);
577 }
578 *_aidl_return = proofOfOwnershipSignature;
579 return Status::ok();
580}
581
David Zeuthenab3e5652019-10-28 13:32:48 -0400582Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400583 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500584 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
585 if (!status.isOk()) {
586 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400587 }
588
589 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
590 "ephemeralKey", // Alias for key
591 "0", // Serial, as a decimal number
592 "Credstore", // Issuer
593 "Ephemeral Key", // Subject
594 0, // Validity Not Before
595 24 * 60 * 60); // Validity Not After
596 if (!pkcs12Bytes) {
597 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
598 "Error creating PKCS#12 structure for key pair");
599 }
600 *_aidl_return = pkcs12Bytes.value();
601 return Status::ok();
602}
603
604Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500605 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
606 if (!status.isOk()) {
607 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400608 }
609 return Status::ok();
610}
611
612Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400613 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
614 if (!data->loadFromDisk()) {
615 LOG(ERROR) << "Error loading data for credential";
616 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
617 "Error loading data for credential");
618 }
619 data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
620 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400621 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
622 "Error saving data");
623 }
624 return Status::ok();
625}
626
627Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400628 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
629 if (!data->loadFromDisk()) {
630 LOG(ERROR) << "Error loading data for credential";
631 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
632 "Error loading data for credential");
633 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400634 optional<vector<vector<uint8_t>>> keysNeedingCert =
David Zeuthen472e6c82020-10-16 11:50:13 -0400635 data->getAuthKeysNeedingCertification(halBinder_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400636 if (!keysNeedingCert) {
637 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
638 "Error getting auth keys neededing certification");
639 }
640 vector<AuthKeyParcel> authKeyParcels;
641 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
642 AuthKeyParcel authKeyParcel;
643 authKeyParcel.x509cert = key;
644 authKeyParcels.push_back(authKeyParcel);
645 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400646 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400647 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
648 "Error saving data");
649 }
650 *_aidl_return = authKeyParcels;
651 return Status::ok();
652}
653
654Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
655 const vector<uint8_t>& staticAuthData) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400656 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
657 if (!data->loadFromDisk()) {
658 LOG(ERROR) << "Error loading data for credential";
659 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
660 "Error loading data for credential");
661 }
662 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
663 std::numeric_limits<int64_t>::max(), staticAuthData)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400664 return Status::fromServiceSpecificError(
665 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
666 "Error finding authentication key to store static "
667 "authentication data for");
668 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400669 if (!data->saveToDisk()) {
670 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
671 "Error saving data");
672 }
673 return Status::ok();
674}
675
676Status
677Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
678 int64_t expirationDateMillisSinceEpoch,
679 const vector<uint8_t>& staticAuthData) {
680 if (halApiVersion_ < 3) {
681 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
682 "Not implemented by HAL");
683 }
684 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
685 if (!data->loadFromDisk()) {
686 LOG(ERROR) << "Error loading data for credential";
687 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
688 "Error loading data for credential");
689 }
690 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
691 expirationDateMillisSinceEpoch, staticAuthData)) {
692 return Status::fromServiceSpecificError(
693 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
694 "Error finding authentication key to store static "
695 "authentication data for");
696 }
697 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400698 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
699 "Error saving data");
700 }
701 return Status::ok();
702}
703
704Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400705 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
706 if (!data->loadFromDisk()) {
707 LOG(ERROR) << "Error loading data for credential";
708 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
709 "Error loading data for credential");
710 }
711 const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
David Zeuthenab3e5652019-10-28 13:32:48 -0400712 vector<int32_t> ret;
713 for (const AuthKeyData& authKeyData : authKeyDatas) {
714 ret.push_back(authKeyData.useCount);
715 }
716 *_aidl_return = ret;
717 return Status::ok();
718}
719
David Zeuthen472e6c82020-10-16 11:50:13 -0400720optional<string> extractDocType(const vector<uint8_t>& credentialData) {
721 auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
722 if (item == nullptr) {
723 LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
724 return {};
725 }
726 const cppbor::Array* array = item->asArray();
727 if (array == nullptr || array->size() < 1) {
728 LOG(ERROR) << "CredentialData array with at least one element";
729 return {};
730 }
731 const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
732 if (tstr == nullptr) {
733 LOG(ERROR) << "First item in CredentialData is not a string";
734 return {};
735 }
736 return tstr->value();
737}
738
739Status Credential::update(sp<IWritableCredential>* _aidl_return) {
740 if (halApiVersion_ < 3) {
741 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
742 "Not implemented by HAL");
743 }
744 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
745 if (!data->loadFromDisk()) {
746 LOG(ERROR) << "Error loading data for credential";
747 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
748 "Error loading data for credential");
749 }
750
751 sp<IWritableIdentityCredential> halWritableCredential;
752 Status status = halBinder_->updateCredential(&halWritableCredential);
753 if (!status.isOk()) {
754 return halStatusToGenericError(status);
755 }
756
757 optional<string> docType = extractDocType(data->getCredentialData());
758 if (!docType) {
759 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
760 "Unable to extract DocType from CredentialData");
761 }
762
763 // NOTE: The caller is expected to call WritableCredential::personalize() which will
764 // write brand new data to disk, specifically it will overwrite any data already
765 // have _including_ authentication keys.
766 //
767 // It is because of this we need to set the CredentialKey certificate chain,
768 // keyCount, and maxUsesPerKey below.
David Zeuthen27407a52021-03-04 16:32:43 -0500769 sp<WritableCredential> writableCredential = new WritableCredential(
770 dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
David Zeuthen472e6c82020-10-16 11:50:13 -0400771
772 writableCredential->setAttestationCertificate(data->getAttestationCertificate());
773 auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
774 writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
775
David Zeuthen27407a52021-03-04 16:32:43 -0500776 // Because its data has changed, we need to replace the binder for the
777 // IIdentityCredential when the credential has been updated... otherwise the
778 // remote object will have stale data for future calls, for example
779 // getAuthKeysNeedingCertification().
David Zeuthen472e6c82020-10-16 11:50:13 -0400780 //
David Zeuthen27407a52021-03-04 16:32:43 -0500781 // The way this is implemented is that setCredentialToReloadWhenUpdated()
782 // instructs the WritableCredential to call writableCredentialPersonalized()
783 // on |this|.
David Zeuthen472e6c82020-10-16 11:50:13 -0400784 //
David Zeuthen27407a52021-03-04 16:32:43 -0500785 //
786 writableCredential->setCredentialToReloadWhenUpdated(this);
David Zeuthen472e6c82020-10-16 11:50:13 -0400787
788 *_aidl_return = writableCredential;
789 return Status::ok();
790}
791
David Zeuthen27407a52021-03-04 16:32:43 -0500792void Credential::writableCredentialPersonalized() {
793 Status status = ensureOrReplaceHalBinder();
794 if (!status.isOk()) {
795 LOG(ERROR) << "Error reloading credential";
796 }
797}
798
David Zeuthenab3e5652019-10-28 13:32:48 -0400799} // namespace identity
800} // namespace security
801} // namespace android