blob: 4a2bae17e0d10506c39158fcbc784141904d8ee7 [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>
20
21#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
36#include "Credential.h"
37#include "CredentialData.h"
38#include "Util.h"
David Zeuthen472e6c82020-10-16 11:50:13 -040039#include "WritableCredential.h"
David Zeuthenab3e5652019-10-28 13:32:48 -040040
41namespace android {
42namespace security {
43namespace identity {
44
45using std::optional;
David Zeuthen59102f32020-05-08 10:58:09 -040046using std::promise;
47using std::tuple;
David Zeuthenab3e5652019-10-28 13:32:48 -040048
49using android::security::keystore::IKeystoreService;
50
David Zeuthen472e6c82020-10-16 11:50:13 -040051using ::android::hardware::identity::IWritableIdentityCredential;
52
David Zeuthenab3e5652019-10-28 13:32:48 -040053using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
54using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
55using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
56using ::android::hardware::identity::support::sha256;
57
58using android::hardware::keymaster::V4_0::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040059using android::hardware::keymaster::V4_0::VerificationToken;
David Zeuthena6f9fba2020-02-11 22:08:27 -050060using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -040061using AidlVerificationToken = android::hardware::keymaster::VerificationToken;
David Zeuthenab3e5652019-10-28 13:32:48 -040062
David Zeuthena6f9fba2020-02-11 22:08:27 -050063Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
David Zeuthen472e6c82020-10-16 11:50:13 -040064 const std::string& credentialName, uid_t callingUid,
65 HardwareInformation hwInfo, sp<IIdentityCredentialStore> halStoreBinder,
66 int halApiVersion)
67 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName),
68 callingUid_(callingUid), hwInfo_(std::move(hwInfo)), halStoreBinder_(halStoreBinder),
69 halApiVersion_(halApiVersion) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040070
71Credential::~Credential() {}
72
David Zeuthen472e6c82020-10-16 11:50:13 -040073Status Credential::ensureOrReplaceHalBinder() {
74 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
David Zeuthenab3e5652019-10-28 13:32:48 -040075 if (!data->loadFromDisk()) {
76 LOG(ERROR) << "Error loading data for credential";
77 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
78 "Error loading data for credential");
79 }
80
David Zeuthenab3e5652019-10-28 13:32:48 -040081 sp<IIdentityCredential> halBinder;
David Zeuthena6f9fba2020-02-11 22:08:27 -050082 Status status =
David Zeuthen472e6c82020-10-16 11:50:13 -040083 halStoreBinder_->getCredential(cipherSuite_, data->getCredentialData(), &halBinder);
David Zeuthena6f9fba2020-02-11 22:08:27 -050084 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
85 int code = status.serviceSpecificErrorCode();
86 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
87 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
88 }
89 }
90 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -040091 LOG(ERROR) << "Error getting HAL binder";
92 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
93 }
David Zeuthenab3e5652019-10-28 13:32:48 -040094 halBinder_ = halBinder;
95
96 return Status::ok();
97}
98
99Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400100 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
101 if (!data->loadFromDisk()) {
102 LOG(ERROR) << "Error loading data for credential";
103 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
104 "Error loading data for credential");
105 }
106 *_aidl_return = data->getAttestationCertificate();
David Zeuthenab3e5652019-10-28 13:32:48 -0400107 return Status::ok();
108}
109
110// Returns operation handle
David Zeuthen472e6c82020-10-16 11:50:13 -0400111Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
112 int64_t* _aidl_return) {
113 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 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400119
David Zeuthen472e6c82020-10-16 11:50:13 -0400120 selectedAuthKey_ = data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
David Zeuthenab3e5652019-10-28 13:32:48 -0400121 if (selectedAuthKey_ == nullptr) {
122 return Status::fromServiceSpecificError(
123 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
124 "No suitable authentication key available");
125 }
126
David Zeuthena6f9fba2020-02-11 22:08:27 -0500127 int64_t challenge;
128 Status status = halBinder_->createAuthChallenge(&challenge);
129 if (!status.isOk()) {
130 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400131 }
132 if (challenge == 0) {
133 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
134 "Returned challenge is 0 (bug in HAL or TA)");
135 }
136
137 selectedChallenge_ = challenge;
138 *_aidl_return = challenge;
139 return Status::ok();
140}
141
David Zeuthen59102f32020-05-08 10:58:09 -0400142class CredstoreTokenCallback : public android::security::keystore::BnCredstoreTokenCallback,
143 public promise<tuple<bool, vector<uint8_t>, vector<uint8_t>>> {
144 public:
145 CredstoreTokenCallback() {}
146 virtual Status onFinished(bool success, const vector<uint8_t>& authToken,
147 const vector<uint8_t>& verificationToken) override {
148 this->set_value({success, authToken, verificationToken});
149 return Status::ok();
150 }
151};
152
David Zeuthenab3e5652019-10-28 13:32:48 -0400153// Returns false if an error occurred communicating with keystore.
154//
David Zeuthen59102f32020-05-08 10:58:09 -0400155bool getTokensFromKeystore(uint64_t challenge, uint64_t secureUserId,
156 unsigned int authTokenMaxAgeMillis, vector<uint8_t>& authToken,
157 vector<uint8_t>& verificationToken) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400158 sp<IServiceManager> sm = defaultServiceManager();
159 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
160 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
161 if (keystore == nullptr) {
162 return false;
163 }
164
David Zeuthen59102f32020-05-08 10:58:09 -0400165 sp<CredstoreTokenCallback> callback = new CredstoreTokenCallback();
166 auto future = callback->get_future();
167
168 Status status =
169 keystore->getTokensForCredstore(challenge, secureUserId, authTokenMaxAgeMillis, callback);
170 if (!status.isOk()) {
171 return false;
172 }
173
174 auto fstatus = future.wait_for(std::chrono::milliseconds(5000));
175 if (fstatus != std::future_status::ready) {
176 LOG(ERROR) << "Waited 5 seconds from tokens for credstore, aborting";
177 return false;
178 }
179 auto [success, returnedAuthToken, returnedVerificationToken] = future.get();
180 if (!success) {
181 LOG(ERROR) << "Error getting tokens from credstore";
David Zeuthenab3e5652019-10-28 13:32:48 -0400182 return false;
183 }
184 authToken = returnedAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400185 verificationToken = returnedVerificationToken;
David Zeuthenab3e5652019-10-28 13:32:48 -0400186 return true;
187}
188
189Status Credential::getEntries(const vector<uint8_t>& requestMessage,
190 const vector<RequestNamespaceParcel>& requestNamespaces,
191 const vector<uint8_t>& sessionTranscript,
192 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
David Zeuthen472e6c82020-10-16 11:50:13 -0400193 bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400194 GetEntriesResultParcel ret;
195
David Zeuthen472e6c82020-10-16 11:50:13 -0400196 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
197 if (!data->loadFromDisk()) {
198 LOG(ERROR) << "Error loading data for credential";
199 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
200 "Error loading data for credential");
201 }
202
David Zeuthenab3e5652019-10-28 13:32:48 -0400203 // Calculate requestCounts ahead of time and be careful not to include
204 // elements that don't exist.
205 //
206 // Also go through and figure out which access control profiles to include
207 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500208 vector<int32_t> requestCounts;
David Zeuthen472e6c82020-10-16 11:50:13 -0400209 const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
David Zeuthen52630002020-07-10 14:10:05 -0400210
211 // We don't support ACP identifiers which isn't in the range 0 to 31. This
212 // guarantee exists so it's feasible to implement the TA part of an Identity
213 // Credential HAL implementation where the TA uses a 32-bit word to indicate
214 // which profiles are authorized.
215 for (const SecureAccessControlProfile& profile : allProfiles) {
216 if (profile.id < 0 || profile.id >= 32) {
217 return Status::fromServiceSpecificError(
218 ICredentialStore::ERROR_GENERIC,
219 "Invalid accessProfileId in profile (must be between 0 and 31)");
220 }
221 }
222
223 vector<bool> includeProfile(32);
224
David Zeuthenab3e5652019-10-28 13:32:48 -0400225 for (const RequestNamespaceParcel& rns : requestNamespaces) {
226 size_t numEntriesInNsToRequest = 0;
227 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400228 if (data->hasEntryData(rns.namespaceName, rep.name)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400229 numEntriesInNsToRequest++;
230 }
231
David Zeuthen472e6c82020-10-16 11:50:13 -0400232 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
233 if (eData) {
234 for (int32_t id : eData.value().accessControlProfileIds) {
David Zeuthen52630002020-07-10 14:10:05 -0400235 if (id < 0 || id >= 32) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400236 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
237 << rns.namespaceName << ": " << rep.name;
238 return Status::fromServiceSpecificError(
David Zeuthen52630002020-07-10 14:10:05 -0400239 ICredentialStore::ERROR_GENERIC,
240 "Invalid accessProfileId in entry (must be between 0 and 31)");
David Zeuthenab3e5652019-10-28 13:32:48 -0400241 }
242 includeProfile[id] = true;
243 }
244 }
245 }
246 requestCounts.push_back(numEntriesInNsToRequest);
247 }
248
249 // Now that we know which profiles are needed, send only those to the
250 // HAL.
251 vector<SecureAccessControlProfile> selectedProfiles;
252 for (size_t n = 0; n < allProfiles.size(); n++) {
David Zeuthen52630002020-07-10 14:10:05 -0400253 if (includeProfile[allProfiles[n].id]) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400254 selectedProfiles.push_back(allProfiles[n]);
255 }
256 }
257
258 // Calculate the highest [1] non-zero timeout and if user-auth is needed
259 // ... we need this to select an appropriate authToken.
260 //
261 // [1] : Why do we request the highest timeout and not the lowest? Well, we
262 // return partial results in getEntries e.g. if some data elements
263 // fail to authorize we'll still return the ones that did not fail. So
264 // e.g. consider data elements A and B where A has an ACP with 60
265 // seconds and B has an ACP with 3600 seconds. In this case we'll be
266 // fine with getting an authToken for e.g. 2400 seconds which would
267 // mean returning only B.
268 //
269 bool userAuthNeeded = false;
270 unsigned int authTokenMaxAgeMillis = 0;
271 for (auto& profile : selectedProfiles) {
272 if (profile.userAuthenticationRequired) {
273 userAuthNeeded = true;
274 if (profile.timeoutMillis > 0) {
275 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
276 authTokenMaxAgeMillis = profile.timeoutMillis;
277 }
278 }
279 }
280 }
281
282 // If requesting a challenge-based authToken the idea is that authentication
283 // happens as part of the transaction. As such, authTokenMaxAgeMillis should
284 // be nearly zero. We'll use 10 seconds for this.
285 if (userAuthNeeded && selectedChallenge_ != 0) {
286 authTokenMaxAgeMillis = 10 * 1000;
287 }
288
David Zeuthen59102f32020-05-08 10:58:09 -0400289 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
290 // is needed in any of the access control profiles for data items being requested.
291 //
David Zeuthena6f9fba2020-02-11 22:08:27 -0500292 AidlHardwareAuthToken aidlAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400293 AidlVerificationToken aidlVerificationToken;
294 aidlAuthToken.challenge = 0;
295 aidlAuthToken.userId = 0;
296 aidlAuthToken.authenticatorId = 0;
297 aidlAuthToken.authenticatorType =
298 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
299 aidlAuthToken.timestamp.milliSeconds = 0;
300 aidlAuthToken.mac.clear();
301 aidlVerificationToken.challenge = 0;
302 aidlVerificationToken.timestamp.milliSeconds = 0;
303 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
304 aidlVerificationToken.mac.clear();
David Zeuthenab3e5652019-10-28 13:32:48 -0400305 if (userAuthNeeded) {
306 vector<uint8_t> authTokenBytes;
David Zeuthen59102f32020-05-08 10:58:09 -0400307 vector<uint8_t> verificationTokenBytes;
David Zeuthen472e6c82020-10-16 11:50:13 -0400308 if (!getTokensFromKeystore(selectedChallenge_, data->getSecureUserId(),
David Zeuthen59102f32020-05-08 10:58:09 -0400309 authTokenMaxAgeMillis, authTokenBytes, verificationTokenBytes)) {
310 LOG(ERROR) << "Error getting tokens from keystore";
David Zeuthenab3e5652019-10-28 13:32:48 -0400311 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
David Zeuthen59102f32020-05-08 10:58:09 -0400312 "Error getting tokens from keystore");
David Zeuthenab3e5652019-10-28 13:32:48 -0400313 }
David Zeuthen59102f32020-05-08 10:58:09 -0400314
315 // It's entirely possible getTokensFromKeystore() succeeded but didn't
316 // return any tokens (in which case the returned byte-vectors are
317 // empty). For example, this can happen if no auth token is available
318 // which satifies e.g. |authTokenMaxAgeMillis|.
319 //
David Zeuthenab3e5652019-10-28 13:32:48 -0400320 if (authTokenBytes.size() > 0) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500321 HardwareAuthToken authToken =
David Zeuthenab3e5652019-10-28 13:32:48 -0400322 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(authTokenBytes);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500323 // Convert from HIDL to AIDL...
324 aidlAuthToken.challenge = int64_t(authToken.challenge);
325 aidlAuthToken.userId = int64_t(authToken.userId);
326 aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
327 aidlAuthToken.authenticatorType =
328 ::android::hardware::keymaster::HardwareAuthenticatorType(
329 int32_t(authToken.authenticatorType));
330 aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
331 aidlAuthToken.mac = authToken.mac;
David Zeuthenab3e5652019-10-28 13:32:48 -0400332 }
David Zeuthen59102f32020-05-08 10:58:09 -0400333
334 if (verificationTokenBytes.size() > 0) {
335 optional<VerificationToken> token =
336 android::hardware::keymaster::V4_0::support::deserializeVerificationToken(
337 verificationTokenBytes);
338 if (!token) {
339 LOG(ERROR) << "Error deserializing verification token";
340 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
341 "Error deserializing verification token");
342 }
343 aidlVerificationToken.challenge = token->challenge;
344 aidlVerificationToken.timestamp.milliSeconds = token->timestamp;
345 aidlVerificationToken.securityLevel =
346 ::android::hardware::keymaster::SecurityLevel(token->securityLevel);
347 aidlVerificationToken.mac = token->mac;
348 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400349 }
350
David Zeuthen55975ec2020-02-27 14:28:18 -0500351 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
352 // the Java layer. So we could end up with no previously selected auth key and we may
353 // need one.
354 const AuthKeyData* authKey = selectedAuthKey_;
355 if (sessionTranscript.size() > 0) {
356 if (authKey == nullptr) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400357 authKey = data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
David Zeuthen55975ec2020-02-27 14:28:18 -0500358 if (authKey == nullptr) {
359 return Status::fromServiceSpecificError(
360 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
361 "No suitable authentication key available");
362 }
363 }
364 }
365 vector<uint8_t> signingKeyBlob;
366 if (authKey != nullptr) {
367 signingKeyBlob = authKey->keyBlob;
368 }
369
David Zeuthene2a78a42020-04-27 13:34:38 -0400370 // Pass the HAL enough information to allow calculating the size of
371 // DeviceNameSpaces ahead of time.
372 vector<RequestNamespace> halRequestNamespaces;
373 for (const RequestNamespaceParcel& rns : requestNamespaces) {
374 RequestNamespace ns;
375 ns.namespaceName = rns.namespaceName;
376 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400377 optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
David Zeuthene2a78a42020-04-27 13:34:38 -0400378 if (entryData) {
379 RequestDataItem di;
380 di.name = rep.name;
381 di.size = entryData.value().size;
382 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
383 ns.items.push_back(di);
384 }
385 }
386 if (ns.items.size() > 0) {
387 halRequestNamespaces.push_back(ns);
388 }
389 }
390 // This is not catastrophic, we might be dealing with a version 1 implementation which
391 // doesn't have this method.
392 Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces);
393 if (!status.isOk()) {
David Zeuthen59102f32020-05-08 10:58:09 -0400394 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
395 << "and continuing";
396 }
397
398 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
399 status = halBinder_->setVerificationToken(aidlVerificationToken);
400 if (!status.isOk()) {
401 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
David Zeuthene2a78a42020-04-27 13:34:38 -0400402 << "and continuing";
403 }
404
405 status =
David Zeuthen55975ec2020-02-27 14:28:18 -0500406 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
407 sessionTranscript, readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500408 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
409 int code = status.serviceSpecificErrorCode();
410 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
411 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
412 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
413 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
414 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
415 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
416 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
417 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
418 }
419 }
420 if (!status.isOk()) {
421 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400422 }
423
424 for (const RequestNamespaceParcel& rns : requestNamespaces) {
425 ResultNamespaceParcel resultNamespaceParcel;
426 resultNamespaceParcel.namespaceName = rns.namespaceName;
427
428 for (const RequestEntryParcel& rep : rns.entries) {
429 ResultEntryParcel resultEntryParcel;
430 resultEntryParcel.name = rep.name;
431
David Zeuthen472e6c82020-10-16 11:50:13 -0400432 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
433 if (!eData) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400434 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
435 resultNamespaceParcel.entries.push_back(resultEntryParcel);
436 continue;
437 }
438
David Zeuthena6f9fba2020-02-11 22:08:27 -0500439 status =
David Zeuthen472e6c82020-10-16 11:50:13 -0400440 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
441 eData.value().accessControlProfileIds);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500442 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
443 int code = status.serviceSpecificErrorCode();
444 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
445 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
446 resultNamespaceParcel.entries.push_back(resultEntryParcel);
447 continue;
448 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
449 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
450 resultNamespaceParcel.entries.push_back(resultEntryParcel);
451 continue;
452 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
453 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
454 resultNamespaceParcel.entries.push_back(resultEntryParcel);
455 continue;
456 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
457 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
458 resultNamespaceParcel.entries.push_back(resultEntryParcel);
459 continue;
460 }
461 }
462 if (!status.isOk()) {
463 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400464 }
465
466 vector<uint8_t> value;
David Zeuthen472e6c82020-10-16 11:50:13 -0400467 for (const auto& encryptedChunk : eData.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500468 vector<uint8_t> chunk;
469 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
470 if (!status.isOk()) {
471 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400472 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500473 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400474 }
475
476 resultEntryParcel.status = STATUS_OK;
477 resultEntryParcel.value = value;
478 resultNamespaceParcel.entries.push_back(resultEntryParcel);
479 }
480 ret.resultNamespaces.push_back(resultNamespaceParcel);
481 }
482
David Zeuthen55975ec2020-02-27 14:28:18 -0500483 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500484 if (!status.isOk()) {
485 return halStatusToGenericError(status);
486 }
487 if (authKey != nullptr) {
488 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400489 }
490
491 // Ensure useCount is updated on disk.
492 if (authKey != nullptr) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400493 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400494 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
495 "Error saving data");
496 }
497 }
498
499 *_aidl_return = ret;
500 return Status::ok();
501}
502
503Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500504 vector<uint8_t> proofOfDeletionSignature;
David Zeuthen472e6c82020-10-16 11:50:13 -0400505
506 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
507 if (!data->loadFromDisk()) {
508 LOG(ERROR) << "Error loading data for credential";
509 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
510 "Error loading data for credential");
511 }
512
David Zeuthena6f9fba2020-02-11 22:08:27 -0500513 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
514 if (!status.isOk()) {
515 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400516 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400517 if (!data->deleteCredential()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400518 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
519 "Error deleting credential data on disk");
520 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500521 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400522 return Status::ok();
523}
524
David Zeuthen472e6c82020-10-16 11:50:13 -0400525Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
526 vector<uint8_t>* _aidl_return) {
527 if (halApiVersion_ < 3) {
528 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
529 "Not implemented by HAL");
530 }
531 vector<uint8_t> proofOfDeletionSignature;
532
533 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
534 if (!data->loadFromDisk()) {
535 LOG(ERROR) << "Error loading data for credential";
536 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
537 "Error loading data for credential");
538 }
539
540 Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
541 if (!status.isOk()) {
542 return halStatusToGenericError(status);
543 }
544 if (!data->deleteCredential()) {
545 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
546 "Error deleting credential data on disk");
547 }
548 *_aidl_return = proofOfDeletionSignature;
549 return Status::ok();
550}
551
552Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
553 if (halApiVersion_ < 3) {
554 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
555 "Not implemented by HAL");
556 }
557 vector<uint8_t> proofOfOwnershipSignature;
558 Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
559 if (!status.isOk()) {
560 return halStatusToGenericError(status);
561 }
562 *_aidl_return = proofOfOwnershipSignature;
563 return Status::ok();
564}
565
David Zeuthenab3e5652019-10-28 13:32:48 -0400566Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400567 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500568 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
569 if (!status.isOk()) {
570 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400571 }
572
573 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
574 "ephemeralKey", // Alias for key
575 "0", // Serial, as a decimal number
576 "Credstore", // Issuer
577 "Ephemeral Key", // Subject
578 0, // Validity Not Before
579 24 * 60 * 60); // Validity Not After
580 if (!pkcs12Bytes) {
581 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
582 "Error creating PKCS#12 structure for key pair");
583 }
584 *_aidl_return = pkcs12Bytes.value();
585 return Status::ok();
586}
587
588Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500589 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
590 if (!status.isOk()) {
591 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400592 }
593 return Status::ok();
594}
595
596Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400597 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
598 if (!data->loadFromDisk()) {
599 LOG(ERROR) << "Error loading data for credential";
600 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
601 "Error loading data for credential");
602 }
603 data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
604 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400605 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
606 "Error saving data");
607 }
608 return Status::ok();
609}
610
611Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400612 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
613 if (!data->loadFromDisk()) {
614 LOG(ERROR) << "Error loading data for credential";
615 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
616 "Error loading data for credential");
617 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400618 optional<vector<vector<uint8_t>>> keysNeedingCert =
David Zeuthen472e6c82020-10-16 11:50:13 -0400619 data->getAuthKeysNeedingCertification(halBinder_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400620 if (!keysNeedingCert) {
621 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
622 "Error getting auth keys neededing certification");
623 }
624 vector<AuthKeyParcel> authKeyParcels;
625 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
626 AuthKeyParcel authKeyParcel;
627 authKeyParcel.x509cert = key;
628 authKeyParcels.push_back(authKeyParcel);
629 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400630 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400631 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
632 "Error saving data");
633 }
634 *_aidl_return = authKeyParcels;
635 return Status::ok();
636}
637
638Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
639 const vector<uint8_t>& staticAuthData) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400640 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
641 if (!data->loadFromDisk()) {
642 LOG(ERROR) << "Error loading data for credential";
643 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
644 "Error loading data for credential");
645 }
646 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
647 std::numeric_limits<int64_t>::max(), staticAuthData)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400648 return Status::fromServiceSpecificError(
649 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
650 "Error finding authentication key to store static "
651 "authentication data for");
652 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400653 if (!data->saveToDisk()) {
654 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
655 "Error saving data");
656 }
657 return Status::ok();
658}
659
660Status
661Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
662 int64_t expirationDateMillisSinceEpoch,
663 const vector<uint8_t>& staticAuthData) {
664 if (halApiVersion_ < 3) {
665 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
666 "Not implemented by HAL");
667 }
668 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
669 if (!data->loadFromDisk()) {
670 LOG(ERROR) << "Error loading data for credential";
671 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
672 "Error loading data for credential");
673 }
674 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
675 expirationDateMillisSinceEpoch, staticAuthData)) {
676 return Status::fromServiceSpecificError(
677 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
678 "Error finding authentication key to store static "
679 "authentication data for");
680 }
681 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400682 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
683 "Error saving data");
684 }
685 return Status::ok();
686}
687
688Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400689 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
690 if (!data->loadFromDisk()) {
691 LOG(ERROR) << "Error loading data for credential";
692 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
693 "Error loading data for credential");
694 }
695 const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
David Zeuthenab3e5652019-10-28 13:32:48 -0400696 vector<int32_t> ret;
697 for (const AuthKeyData& authKeyData : authKeyDatas) {
698 ret.push_back(authKeyData.useCount);
699 }
700 *_aidl_return = ret;
701 return Status::ok();
702}
703
David Zeuthen472e6c82020-10-16 11:50:13 -0400704optional<string> extractDocType(const vector<uint8_t>& credentialData) {
705 auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
706 if (item == nullptr) {
707 LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
708 return {};
709 }
710 const cppbor::Array* array = item->asArray();
711 if (array == nullptr || array->size() < 1) {
712 LOG(ERROR) << "CredentialData array with at least one element";
713 return {};
714 }
715 const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
716 if (tstr == nullptr) {
717 LOG(ERROR) << "First item in CredentialData is not a string";
718 return {};
719 }
720 return tstr->value();
721}
722
723Status Credential::update(sp<IWritableCredential>* _aidl_return) {
724 if (halApiVersion_ < 3) {
725 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
726 "Not implemented by HAL");
727 }
728 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
729 if (!data->loadFromDisk()) {
730 LOG(ERROR) << "Error loading data for credential";
731 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
732 "Error loading data for credential");
733 }
734
735 sp<IWritableIdentityCredential> halWritableCredential;
736 Status status = halBinder_->updateCredential(&halWritableCredential);
737 if (!status.isOk()) {
738 return halStatusToGenericError(status);
739 }
740
741 optional<string> docType = extractDocType(data->getCredentialData());
742 if (!docType) {
743 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
744 "Unable to extract DocType from CredentialData");
745 }
746
747 // NOTE: The caller is expected to call WritableCredential::personalize() which will
748 // write brand new data to disk, specifically it will overwrite any data already
749 // have _including_ authentication keys.
750 //
751 // It is because of this we need to set the CredentialKey certificate chain,
752 // keyCount, and maxUsesPerKey below.
753 sp<WritableCredential> writableCredential =
754 new WritableCredential(dataPath_, credentialName_, docType.value(), true, hwInfo_,
755 halWritableCredential, halApiVersion_);
756
757 writableCredential->setAttestationCertificate(data->getAttestationCertificate());
758 auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
759 writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
760
761 // Because its data has changed, we need to reconnect to the HAL when the
762 // credential has been updated... otherwise the remote object will have
763 // stale data for future calls (e.g. getAuthKeysNeedingCertification().
764 //
765 // The joys and pitfalls of mutable objects...
766 //
767 writableCredential->setCredentialUpdatedCallback([this] {
768 Status status = this->ensureOrReplaceHalBinder();
769 if (!status.isOk()) {
770 LOG(ERROR) << "Error loading credential";
771 }
772 });
773
774 *_aidl_return = writableCredential;
775 return Status::ok();
776}
777
David Zeuthenab3e5652019-10-28 13:32:48 -0400778} // namespace identity
779} // namespace security
780} // namespace android