blob: a3c72edc8a6297c0b63bc457486e97977a646adc [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 Zeuthen27407a52021-03-04 16:32:43 -0500120 // We just check if a key is available, we actually don't store it since we
121 // don't keep CredentialData around between binder calls.
122 const AuthKeyData* authKey =
123 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
124 if (authKey == nullptr) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400125 return Status::fromServiceSpecificError(
126 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
127 "No suitable authentication key available");
128 }
129
David Zeuthen27407a52021-03-04 16:32:43 -0500130 if (!ensureChallenge()) {
131 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
132 "Error getting challenge (bug in HAL or TA)");
133 }
134 *_aidl_return = selectedChallenge_;
135 return Status::ok();
136}
137
138bool Credential::ensureChallenge() {
139 if (selectedChallenge_ != 0) {
140 return true;
141 }
142
David Zeuthena6f9fba2020-02-11 22:08:27 -0500143 int64_t challenge;
144 Status status = halBinder_->createAuthChallenge(&challenge);
145 if (!status.isOk()) {
David Zeuthen27407a52021-03-04 16:32:43 -0500146 LOG(ERROR) << "Error getting challenge: " << status.exceptionMessage();
147 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400148 }
149 if (challenge == 0) {
David Zeuthen27407a52021-03-04 16:32:43 -0500150 LOG(ERROR) << "Returned challenge is 0 (bug in HAL or TA)";
151 return false;
David Zeuthenab3e5652019-10-28 13:32:48 -0400152 }
153
154 selectedChallenge_ = challenge;
David Zeuthen27407a52021-03-04 16:32:43 -0500155 return true;
David Zeuthenab3e5652019-10-28 13:32:48 -0400156}
157
David Zeuthen59102f32020-05-08 10:58:09 -0400158class CredstoreTokenCallback : public android::security::keystore::BnCredstoreTokenCallback,
159 public promise<tuple<bool, vector<uint8_t>, vector<uint8_t>>> {
160 public:
161 CredstoreTokenCallback() {}
162 virtual Status onFinished(bool success, const vector<uint8_t>& authToken,
163 const vector<uint8_t>& verificationToken) override {
164 this->set_value({success, authToken, verificationToken});
165 return Status::ok();
166 }
167};
168
David Zeuthenab3e5652019-10-28 13:32:48 -0400169// Returns false if an error occurred communicating with keystore.
170//
David Zeuthen59102f32020-05-08 10:58:09 -0400171bool getTokensFromKeystore(uint64_t challenge, uint64_t secureUserId,
172 unsigned int authTokenMaxAgeMillis, vector<uint8_t>& authToken,
173 vector<uint8_t>& verificationToken) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400174 sp<IServiceManager> sm = defaultServiceManager();
175 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
176 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
177 if (keystore == nullptr) {
178 return false;
179 }
180
David Zeuthen59102f32020-05-08 10:58:09 -0400181 sp<CredstoreTokenCallback> callback = new CredstoreTokenCallback();
182 auto future = callback->get_future();
183
184 Status status =
185 keystore->getTokensForCredstore(challenge, secureUserId, authTokenMaxAgeMillis, callback);
186 if (!status.isOk()) {
187 return false;
188 }
189
190 auto fstatus = future.wait_for(std::chrono::milliseconds(5000));
191 if (fstatus != std::future_status::ready) {
192 LOG(ERROR) << "Waited 5 seconds from tokens for credstore, aborting";
193 return false;
194 }
195 auto [success, returnedAuthToken, returnedVerificationToken] = future.get();
196 if (!success) {
197 LOG(ERROR) << "Error getting tokens from credstore";
David Zeuthenab3e5652019-10-28 13:32:48 -0400198 return false;
199 }
200 authToken = returnedAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400201 verificationToken = returnedVerificationToken;
David Zeuthenab3e5652019-10-28 13:32:48 -0400202 return true;
203}
204
205Status Credential::getEntries(const vector<uint8_t>& requestMessage,
206 const vector<RequestNamespaceParcel>& requestNamespaces,
207 const vector<uint8_t>& sessionTranscript,
208 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
David Zeuthen472e6c82020-10-16 11:50:13 -0400209 bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400210 GetEntriesResultParcel ret;
211
David Zeuthen472e6c82020-10-16 11:50:13 -0400212 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
213 if (!data->loadFromDisk()) {
214 LOG(ERROR) << "Error loading data for credential";
215 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
216 "Error loading data for credential");
217 }
218
David Zeuthenab3e5652019-10-28 13:32:48 -0400219 // Calculate requestCounts ahead of time and be careful not to include
220 // elements that don't exist.
221 //
222 // Also go through and figure out which access control profiles to include
223 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500224 vector<int32_t> requestCounts;
David Zeuthen472e6c82020-10-16 11:50:13 -0400225 const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
David Zeuthen52630002020-07-10 14:10:05 -0400226
227 // We don't support ACP identifiers which isn't in the range 0 to 31. This
228 // guarantee exists so it's feasible to implement the TA part of an Identity
229 // Credential HAL implementation where the TA uses a 32-bit word to indicate
230 // which profiles are authorized.
231 for (const SecureAccessControlProfile& profile : allProfiles) {
232 if (profile.id < 0 || profile.id >= 32) {
233 return Status::fromServiceSpecificError(
234 ICredentialStore::ERROR_GENERIC,
235 "Invalid accessProfileId in profile (must be between 0 and 31)");
236 }
237 }
238
239 vector<bool> includeProfile(32);
240
David Zeuthenab3e5652019-10-28 13:32:48 -0400241 for (const RequestNamespaceParcel& rns : requestNamespaces) {
242 size_t numEntriesInNsToRequest = 0;
243 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400244 if (data->hasEntryData(rns.namespaceName, rep.name)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400245 numEntriesInNsToRequest++;
246 }
247
David Zeuthen472e6c82020-10-16 11:50:13 -0400248 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
249 if (eData) {
250 for (int32_t id : eData.value().accessControlProfileIds) {
David Zeuthen52630002020-07-10 14:10:05 -0400251 if (id < 0 || id >= 32) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400252 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
253 << rns.namespaceName << ": " << rep.name;
254 return Status::fromServiceSpecificError(
David Zeuthen52630002020-07-10 14:10:05 -0400255 ICredentialStore::ERROR_GENERIC,
256 "Invalid accessProfileId in entry (must be between 0 and 31)");
David Zeuthenab3e5652019-10-28 13:32:48 -0400257 }
258 includeProfile[id] = true;
259 }
260 }
261 }
262 requestCounts.push_back(numEntriesInNsToRequest);
263 }
264
265 // Now that we know which profiles are needed, send only those to the
266 // HAL.
267 vector<SecureAccessControlProfile> selectedProfiles;
268 for (size_t n = 0; n < allProfiles.size(); n++) {
David Zeuthen52630002020-07-10 14:10:05 -0400269 if (includeProfile[allProfiles[n].id]) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400270 selectedProfiles.push_back(allProfiles[n]);
271 }
272 }
273
274 // Calculate the highest [1] non-zero timeout and if user-auth is needed
275 // ... we need this to select an appropriate authToken.
276 //
277 // [1] : Why do we request the highest timeout and not the lowest? Well, we
278 // return partial results in getEntries e.g. if some data elements
279 // fail to authorize we'll still return the ones that did not fail. So
280 // e.g. consider data elements A and B where A has an ACP with 60
281 // seconds and B has an ACP with 3600 seconds. In this case we'll be
282 // fine with getting an authToken for e.g. 2400 seconds which would
283 // mean returning only B.
284 //
285 bool userAuthNeeded = false;
286 unsigned int authTokenMaxAgeMillis = 0;
287 for (auto& profile : selectedProfiles) {
288 if (profile.userAuthenticationRequired) {
289 userAuthNeeded = true;
290 if (profile.timeoutMillis > 0) {
291 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
292 authTokenMaxAgeMillis = profile.timeoutMillis;
293 }
294 }
295 }
296 }
297
David Zeuthen59102f32020-05-08 10:58:09 -0400298 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
299 // is needed in any of the access control profiles for data items being requested.
300 //
David Zeuthena6f9fba2020-02-11 22:08:27 -0500301 AidlHardwareAuthToken aidlAuthToken;
David Zeuthen59102f32020-05-08 10:58:09 -0400302 AidlVerificationToken aidlVerificationToken;
303 aidlAuthToken.challenge = 0;
304 aidlAuthToken.userId = 0;
305 aidlAuthToken.authenticatorId = 0;
306 aidlAuthToken.authenticatorType =
307 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
308 aidlAuthToken.timestamp.milliSeconds = 0;
309 aidlAuthToken.mac.clear();
310 aidlVerificationToken.challenge = 0;
311 aidlVerificationToken.timestamp.milliSeconds = 0;
312 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
313 aidlVerificationToken.mac.clear();
David Zeuthenab3e5652019-10-28 13:32:48 -0400314 if (userAuthNeeded) {
David Zeuthen27407a52021-03-04 16:32:43 -0500315 // If user authentication is needed, always get a challenge from the
316 // HAL/TA since it'll need it to check the returned VerificationToken
317 // for freshness.
318 if (!ensureChallenge()) {
319 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
320 "Error getting challenge (bug in HAL or TA)");
321 }
322
323 // Note: if all selected profiles require auth-on-every-presentation
324 // then authTokenMaxAgeMillis will be 0 (because timeoutMillis for each
325 // profile is 0). Which means that keystore will only return an
326 // AuthToken if its challenge matches what we pass, regardless of its
327 // age. This is intended b/c the HAL/TA will check not care about
328 // the age in this case, it only cares that the challenge matches.
329 //
330 // Otherwise, if one or more of the profiles is auth-with-a-timeout then
331 // authTokenMaxAgeMillis will be set to the largest of those
332 // timeouts. We'll get an AuthToken which satisfies this deadline if it
333 // exists. This authToken _may_ have the requested challenge but it's
334 // not a guarantee and it's also not required.
335 //
336
David Zeuthenab3e5652019-10-28 13:32:48 -0400337 vector<uint8_t> authTokenBytes;
David Zeuthen59102f32020-05-08 10:58:09 -0400338 vector<uint8_t> verificationTokenBytes;
David Zeuthen472e6c82020-10-16 11:50:13 -0400339 if (!getTokensFromKeystore(selectedChallenge_, data->getSecureUserId(),
David Zeuthen59102f32020-05-08 10:58:09 -0400340 authTokenMaxAgeMillis, authTokenBytes, verificationTokenBytes)) {
341 LOG(ERROR) << "Error getting tokens from keystore";
David Zeuthenab3e5652019-10-28 13:32:48 -0400342 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
David Zeuthen59102f32020-05-08 10:58:09 -0400343 "Error getting tokens from keystore");
David Zeuthenab3e5652019-10-28 13:32:48 -0400344 }
David Zeuthen59102f32020-05-08 10:58:09 -0400345
346 // It's entirely possible getTokensFromKeystore() succeeded but didn't
347 // return any tokens (in which case the returned byte-vectors are
348 // empty). For example, this can happen if no auth token is available
349 // which satifies e.g. |authTokenMaxAgeMillis|.
350 //
David Zeuthenab3e5652019-10-28 13:32:48 -0400351 if (authTokenBytes.size() > 0) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500352 HardwareAuthToken authToken =
David Zeuthenab3e5652019-10-28 13:32:48 -0400353 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(authTokenBytes);
David Zeuthen27407a52021-03-04 16:32:43 -0500354
David Zeuthena6f9fba2020-02-11 22:08:27 -0500355 // Convert from HIDL to AIDL...
356 aidlAuthToken.challenge = int64_t(authToken.challenge);
357 aidlAuthToken.userId = int64_t(authToken.userId);
358 aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
359 aidlAuthToken.authenticatorType =
360 ::android::hardware::keymaster::HardwareAuthenticatorType(
361 int32_t(authToken.authenticatorType));
362 aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
363 aidlAuthToken.mac = authToken.mac;
David Zeuthenab3e5652019-10-28 13:32:48 -0400364 }
David Zeuthen59102f32020-05-08 10:58:09 -0400365
366 if (verificationTokenBytes.size() > 0) {
367 optional<VerificationToken> token =
368 android::hardware::keymaster::V4_0::support::deserializeVerificationToken(
369 verificationTokenBytes);
370 if (!token) {
371 LOG(ERROR) << "Error deserializing verification token";
372 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
373 "Error deserializing verification token");
374 }
375 aidlVerificationToken.challenge = token->challenge;
376 aidlVerificationToken.timestamp.milliSeconds = token->timestamp;
377 aidlVerificationToken.securityLevel =
378 ::android::hardware::keymaster::SecurityLevel(token->securityLevel);
379 aidlVerificationToken.mac = token->mac;
380 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400381 }
382
David Zeuthen55975ec2020-02-27 14:28:18 -0500383 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
384 // the Java layer. So we could end up with no previously selected auth key and we may
385 // need one.
David Zeuthen27407a52021-03-04 16:32:43 -0500386 //
387 const AuthKeyData* authKey =
388 data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
389 if (authKey == nullptr) {
390 // If no authKey is available, consider it an error only when a
391 // SessionTranscript was provided.
392 //
393 // We allow no SessionTranscript to be provided because it makes
394 // the API simpler to deal with insofar it can be used without having
395 // to generate any authentication keys.
396 //
397 // In this "no SessionTranscript is provided" mode we don't return
398 // DeviceNameSpaces nor a MAC over DeviceAuthentication so we don't
399 // need a device key.
400 //
401 if (sessionTranscript.size() > 0) {
402 return Status::fromServiceSpecificError(
403 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
404 "No suitable authentication key available and one is needed");
David Zeuthen55975ec2020-02-27 14:28:18 -0500405 }
406 }
407 vector<uint8_t> signingKeyBlob;
408 if (authKey != nullptr) {
409 signingKeyBlob = authKey->keyBlob;
410 }
411
David Zeuthene2a78a42020-04-27 13:34:38 -0400412 // Pass the HAL enough information to allow calculating the size of
413 // DeviceNameSpaces ahead of time.
414 vector<RequestNamespace> halRequestNamespaces;
415 for (const RequestNamespaceParcel& rns : requestNamespaces) {
416 RequestNamespace ns;
417 ns.namespaceName = rns.namespaceName;
418 for (const RequestEntryParcel& rep : rns.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400419 optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
David Zeuthene2a78a42020-04-27 13:34:38 -0400420 if (entryData) {
421 RequestDataItem di;
422 di.name = rep.name;
423 di.size = entryData.value().size;
424 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
425 ns.items.push_back(di);
426 }
427 }
428 if (ns.items.size() > 0) {
429 halRequestNamespaces.push_back(ns);
430 }
431 }
432 // This is not catastrophic, we might be dealing with a version 1 implementation which
433 // doesn't have this method.
434 Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces);
435 if (!status.isOk()) {
David Zeuthen59102f32020-05-08 10:58:09 -0400436 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
437 << "and continuing";
438 }
439
440 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
441 status = halBinder_->setVerificationToken(aidlVerificationToken);
442 if (!status.isOk()) {
443 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
David Zeuthene2a78a42020-04-27 13:34:38 -0400444 << "and continuing";
445 }
446
447 status =
David Zeuthen55975ec2020-02-27 14:28:18 -0500448 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
449 sessionTranscript, readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500450 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
451 int code = status.serviceSpecificErrorCode();
452 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
453 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
454 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
455 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
456 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
457 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
458 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
459 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
460 }
461 }
462 if (!status.isOk()) {
463 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400464 }
465
466 for (const RequestNamespaceParcel& rns : requestNamespaces) {
467 ResultNamespaceParcel resultNamespaceParcel;
468 resultNamespaceParcel.namespaceName = rns.namespaceName;
469
470 for (const RequestEntryParcel& rep : rns.entries) {
471 ResultEntryParcel resultEntryParcel;
472 resultEntryParcel.name = rep.name;
473
David Zeuthen472e6c82020-10-16 11:50:13 -0400474 optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
475 if (!eData) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400476 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
477 resultNamespaceParcel.entries.push_back(resultEntryParcel);
478 continue;
479 }
480
David Zeuthena6f9fba2020-02-11 22:08:27 -0500481 status =
David Zeuthen472e6c82020-10-16 11:50:13 -0400482 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
483 eData.value().accessControlProfileIds);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500484 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
485 int code = status.serviceSpecificErrorCode();
486 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
487 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
488 resultNamespaceParcel.entries.push_back(resultEntryParcel);
489 continue;
490 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
491 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
492 resultNamespaceParcel.entries.push_back(resultEntryParcel);
493 continue;
494 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
495 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
496 resultNamespaceParcel.entries.push_back(resultEntryParcel);
497 continue;
498 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
499 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
500 resultNamespaceParcel.entries.push_back(resultEntryParcel);
501 continue;
502 }
503 }
504 if (!status.isOk()) {
505 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400506 }
507
508 vector<uint8_t> value;
David Zeuthen472e6c82020-10-16 11:50:13 -0400509 for (const auto& encryptedChunk : eData.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500510 vector<uint8_t> chunk;
511 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
512 if (!status.isOk()) {
513 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400514 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500515 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400516 }
517
518 resultEntryParcel.status = STATUS_OK;
519 resultEntryParcel.value = value;
520 resultNamespaceParcel.entries.push_back(resultEntryParcel);
521 }
522 ret.resultNamespaces.push_back(resultNamespaceParcel);
523 }
524
David Zeuthen55975ec2020-02-27 14:28:18 -0500525 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500526 if (!status.isOk()) {
527 return halStatusToGenericError(status);
528 }
529 if (authKey != nullptr) {
530 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400531 }
532
533 // Ensure useCount is updated on disk.
534 if (authKey != nullptr) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400535 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400536 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
537 "Error saving data");
538 }
539 }
540
541 *_aidl_return = ret;
542 return Status::ok();
543}
544
545Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500546 vector<uint8_t> proofOfDeletionSignature;
David Zeuthen472e6c82020-10-16 11:50:13 -0400547
548 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
549 if (!data->loadFromDisk()) {
550 LOG(ERROR) << "Error loading data for credential";
551 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
552 "Error loading data for credential");
553 }
554
David Zeuthena6f9fba2020-02-11 22:08:27 -0500555 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
556 if (!status.isOk()) {
557 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400558 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400559 if (!data->deleteCredential()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400560 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
561 "Error deleting credential data on disk");
562 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500563 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400564 return Status::ok();
565}
566
David Zeuthen472e6c82020-10-16 11:50:13 -0400567Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
568 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> proofOfDeletionSignature;
574
575 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
576 if (!data->loadFromDisk()) {
577 LOG(ERROR) << "Error loading data for credential";
578 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
579 "Error loading data for credential");
580 }
581
582 Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
583 if (!status.isOk()) {
584 return halStatusToGenericError(status);
585 }
586 if (!data->deleteCredential()) {
587 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
588 "Error deleting credential data on disk");
589 }
590 *_aidl_return = proofOfDeletionSignature;
591 return Status::ok();
592}
593
594Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
595 if (halApiVersion_ < 3) {
596 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
597 "Not implemented by HAL");
598 }
599 vector<uint8_t> proofOfOwnershipSignature;
600 Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
601 if (!status.isOk()) {
602 return halStatusToGenericError(status);
603 }
604 *_aidl_return = proofOfOwnershipSignature;
605 return Status::ok();
606}
607
David Zeuthenab3e5652019-10-28 13:32:48 -0400608Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400609 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500610 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
611 if (!status.isOk()) {
612 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400613 }
614
615 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
616 "ephemeralKey", // Alias for key
617 "0", // Serial, as a decimal number
618 "Credstore", // Issuer
619 "Ephemeral Key", // Subject
620 0, // Validity Not Before
621 24 * 60 * 60); // Validity Not After
622 if (!pkcs12Bytes) {
623 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
624 "Error creating PKCS#12 structure for key pair");
625 }
626 *_aidl_return = pkcs12Bytes.value();
627 return Status::ok();
628}
629
630Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500631 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
632 if (!status.isOk()) {
633 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400634 }
635 return Status::ok();
636}
637
638Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400639 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
640 if (!data->loadFromDisk()) {
641 LOG(ERROR) << "Error loading data for credential";
642 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
643 "Error loading data for credential");
644 }
645 data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
646 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400647 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
648 "Error saving data");
649 }
650 return Status::ok();
651}
652
653Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400654 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
655 if (!data->loadFromDisk()) {
656 LOG(ERROR) << "Error loading data for credential";
657 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
658 "Error loading data for credential");
659 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400660 optional<vector<vector<uint8_t>>> keysNeedingCert =
David Zeuthen472e6c82020-10-16 11:50:13 -0400661 data->getAuthKeysNeedingCertification(halBinder_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400662 if (!keysNeedingCert) {
663 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
664 "Error getting auth keys neededing certification");
665 }
666 vector<AuthKeyParcel> authKeyParcels;
667 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
668 AuthKeyParcel authKeyParcel;
669 authKeyParcel.x509cert = key;
670 authKeyParcels.push_back(authKeyParcel);
671 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400672 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400673 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
674 "Error saving data");
675 }
676 *_aidl_return = authKeyParcels;
677 return Status::ok();
678}
679
680Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
681 const vector<uint8_t>& staticAuthData) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400682 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
683 if (!data->loadFromDisk()) {
684 LOG(ERROR) << "Error loading data for credential";
685 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
686 "Error loading data for credential");
687 }
688 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
689 std::numeric_limits<int64_t>::max(), staticAuthData)) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400690 return Status::fromServiceSpecificError(
691 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
692 "Error finding authentication key to store static "
693 "authentication data for");
694 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400695 if (!data->saveToDisk()) {
696 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
697 "Error saving data");
698 }
699 return Status::ok();
700}
701
702Status
703Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
704 int64_t expirationDateMillisSinceEpoch,
705 const vector<uint8_t>& staticAuthData) {
706 if (halApiVersion_ < 3) {
707 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
708 "Not implemented by HAL");
709 }
710 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
711 if (!data->loadFromDisk()) {
712 LOG(ERROR) << "Error loading data for credential";
713 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
714 "Error loading data for credential");
715 }
716 if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
717 expirationDateMillisSinceEpoch, staticAuthData)) {
718 return Status::fromServiceSpecificError(
719 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
720 "Error finding authentication key to store static "
721 "authentication data for");
722 }
723 if (!data->saveToDisk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400724 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
725 "Error saving data");
726 }
727 return Status::ok();
728}
729
730Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400731 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
732 if (!data->loadFromDisk()) {
733 LOG(ERROR) << "Error loading data for credential";
734 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
735 "Error loading data for credential");
736 }
737 const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
David Zeuthenab3e5652019-10-28 13:32:48 -0400738 vector<int32_t> ret;
739 for (const AuthKeyData& authKeyData : authKeyDatas) {
740 ret.push_back(authKeyData.useCount);
741 }
742 *_aidl_return = ret;
743 return Status::ok();
744}
745
David Zeuthen472e6c82020-10-16 11:50:13 -0400746optional<string> extractDocType(const vector<uint8_t>& credentialData) {
747 auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
748 if (item == nullptr) {
749 LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
750 return {};
751 }
752 const cppbor::Array* array = item->asArray();
753 if (array == nullptr || array->size() < 1) {
754 LOG(ERROR) << "CredentialData array with at least one element";
755 return {};
756 }
757 const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
758 if (tstr == nullptr) {
759 LOG(ERROR) << "First item in CredentialData is not a string";
760 return {};
761 }
762 return tstr->value();
763}
764
765Status Credential::update(sp<IWritableCredential>* _aidl_return) {
766 if (halApiVersion_ < 3) {
767 return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
768 "Not implemented by HAL");
769 }
770 sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
771 if (!data->loadFromDisk()) {
772 LOG(ERROR) << "Error loading data for credential";
773 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
774 "Error loading data for credential");
775 }
776
777 sp<IWritableIdentityCredential> halWritableCredential;
778 Status status = halBinder_->updateCredential(&halWritableCredential);
779 if (!status.isOk()) {
780 return halStatusToGenericError(status);
781 }
782
783 optional<string> docType = extractDocType(data->getCredentialData());
784 if (!docType) {
785 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
786 "Unable to extract DocType from CredentialData");
787 }
788
789 // NOTE: The caller is expected to call WritableCredential::personalize() which will
790 // write brand new data to disk, specifically it will overwrite any data already
791 // have _including_ authentication keys.
792 //
793 // It is because of this we need to set the CredentialKey certificate chain,
794 // keyCount, and maxUsesPerKey below.
David Zeuthen27407a52021-03-04 16:32:43 -0500795 sp<WritableCredential> writableCredential = new WritableCredential(
796 dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
David Zeuthen472e6c82020-10-16 11:50:13 -0400797
798 writableCredential->setAttestationCertificate(data->getAttestationCertificate());
799 auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
800 writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
801
David Zeuthen27407a52021-03-04 16:32:43 -0500802 // Because its data has changed, we need to replace the binder for the
803 // IIdentityCredential when the credential has been updated... otherwise the
804 // remote object will have stale data for future calls, for example
805 // getAuthKeysNeedingCertification().
David Zeuthen472e6c82020-10-16 11:50:13 -0400806 //
David Zeuthen27407a52021-03-04 16:32:43 -0500807 // The way this is implemented is that setCredentialToReloadWhenUpdated()
808 // instructs the WritableCredential to call writableCredentialPersonalized()
809 // on |this|.
David Zeuthen472e6c82020-10-16 11:50:13 -0400810 //
David Zeuthen27407a52021-03-04 16:32:43 -0500811 //
812 writableCredential->setCredentialToReloadWhenUpdated(this);
David Zeuthen472e6c82020-10-16 11:50:13 -0400813
814 *_aidl_return = writableCredential;
815 return Status::ok();
816}
817
David Zeuthen27407a52021-03-04 16:32:43 -0500818void Credential::writableCredentialPersonalized() {
819 Status status = ensureOrReplaceHalBinder();
820 if (!status.isOk()) {
821 LOG(ERROR) << "Error reloading credential";
822 }
823}
824
David Zeuthenab3e5652019-10-28 13:32:48 -0400825} // namespace identity
826} // namespace security
827} // namespace android