1 /*
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
25 #include <android/security/keystore/BnCredstoreTokenCallback.h>
26 #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>
33 #include <future>
34 #include <tuple>
35
36 #include "Credential.h"
37 #include "CredentialData.h"
38 #include "Util.h"
39
40 namespace android {
41 namespace security {
42 namespace identity {
43
44 using std::optional;
45 using std::promise;
46 using std::tuple;
47
48 using android::security::keystore::IKeystoreService;
49
50 using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
51 using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
52 using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
53 using ::android::hardware::identity::support::sha256;
54
55 using android::hardware::keymaster::V4_0::HardwareAuthToken;
56 using android::hardware::keymaster::V4_0::VerificationToken;
57 using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;
58 using AidlVerificationToken = android::hardware::keymaster::VerificationToken;
59
Credential(CipherSuite cipherSuite,const std::string & dataPath,const std::string & credentialName)60 Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
61 const std::string& credentialName)
62 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName) {}
63
~Credential()64 Credential::~Credential() {}
65
loadCredential(sp<IIdentityCredentialStore> halStoreBinder)66 Status Credential::loadCredential(sp<IIdentityCredentialStore> halStoreBinder) {
67 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
68 sp<CredentialData> data = new CredentialData(dataPath_, callingUid, credentialName_);
69 if (!data->loadFromDisk()) {
70 LOG(ERROR) << "Error loading data for credential";
71 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
72 "Error loading data for credential");
73 }
74
75 data_ = data;
76
77 sp<IIdentityCredential> halBinder;
78 Status status =
79 halStoreBinder->getCredential(cipherSuite_, data_->getCredentialData(), &halBinder);
80 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
81 int code = status.serviceSpecificErrorCode();
82 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
83 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
84 }
85 }
86 if (!status.isOk()) {
87 LOG(ERROR) << "Error getting HAL binder";
88 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
89 }
90
91 halBinder_ = halBinder;
92
93 return Status::ok();
94 }
95
getCredentialKeyCertificateChain(std::vector<uint8_t> * _aidl_return)96 Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
97 *_aidl_return = data_->getAttestationCertificate();
98 return Status::ok();
99 }
100
101 // Returns operation handle
selectAuthKey(bool allowUsingExhaustedKeys,int64_t * _aidl_return)102 Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) {
103
104 selectedAuthKey_ = data_->selectAuthKey(allowUsingExhaustedKeys);
105 if (selectedAuthKey_ == nullptr) {
106 return Status::fromServiceSpecificError(
107 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
108 "No suitable authentication key available");
109 }
110
111 int64_t challenge;
112 Status status = halBinder_->createAuthChallenge(&challenge);
113 if (!status.isOk()) {
114 return halStatusToGenericError(status);
115 }
116 if (challenge == 0) {
117 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
118 "Returned challenge is 0 (bug in HAL or TA)");
119 }
120
121 selectedChallenge_ = challenge;
122 *_aidl_return = challenge;
123 return Status::ok();
124 }
125
126 class CredstoreTokenCallback : public android::security::keystore::BnCredstoreTokenCallback,
127 public promise<tuple<bool, vector<uint8_t>, vector<uint8_t>>> {
128 public:
CredstoreTokenCallback()129 CredstoreTokenCallback() {}
onFinished(bool success,const vector<uint8_t> & authToken,const vector<uint8_t> & verificationToken)130 virtual Status onFinished(bool success, const vector<uint8_t>& authToken,
131 const vector<uint8_t>& verificationToken) override {
132 this->set_value({success, authToken, verificationToken});
133 return Status::ok();
134 }
135 };
136
137 // Returns false if an error occurred communicating with keystore.
138 //
getTokensFromKeystore(uint64_t challenge,uint64_t secureUserId,unsigned int authTokenMaxAgeMillis,vector<uint8_t> & authToken,vector<uint8_t> & verificationToken)139 bool getTokensFromKeystore(uint64_t challenge, uint64_t secureUserId,
140 unsigned int authTokenMaxAgeMillis, vector<uint8_t>& authToken,
141 vector<uint8_t>& verificationToken) {
142 sp<IServiceManager> sm = defaultServiceManager();
143 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
144 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
145 if (keystore == nullptr) {
146 return false;
147 }
148
149 sp<CredstoreTokenCallback> callback = new CredstoreTokenCallback();
150 auto future = callback->get_future();
151
152 Status status =
153 keystore->getTokensForCredstore(challenge, secureUserId, authTokenMaxAgeMillis, callback);
154 if (!status.isOk()) {
155 return false;
156 }
157
158 auto fstatus = future.wait_for(std::chrono::milliseconds(5000));
159 if (fstatus != std::future_status::ready) {
160 LOG(ERROR) << "Waited 5 seconds from tokens for credstore, aborting";
161 return false;
162 }
163 auto [success, returnedAuthToken, returnedVerificationToken] = future.get();
164 if (!success) {
165 LOG(ERROR) << "Error getting tokens from credstore";
166 return false;
167 }
168 authToken = returnedAuthToken;
169 verificationToken = returnedVerificationToken;
170 return true;
171 }
172
getEntries(const vector<uint8_t> & requestMessage,const vector<RequestNamespaceParcel> & requestNamespaces,const vector<uint8_t> & sessionTranscript,const vector<uint8_t> & readerSignature,bool allowUsingExhaustedKeys,GetEntriesResultParcel * _aidl_return)173 Status Credential::getEntries(const vector<uint8_t>& requestMessage,
174 const vector<RequestNamespaceParcel>& requestNamespaces,
175 const vector<uint8_t>& sessionTranscript,
176 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
177 GetEntriesResultParcel* _aidl_return) {
178 GetEntriesResultParcel ret;
179
180 // Calculate requestCounts ahead of time and be careful not to include
181 // elements that don't exist.
182 //
183 // Also go through and figure out which access control profiles to include
184 // in the startRetrieval() call.
185 vector<int32_t> requestCounts;
186 const vector<SecureAccessControlProfile>& allProfiles = data_->getSecureAccessControlProfiles();
187
188 // We don't support ACP identifiers which isn't in the range 0 to 31. This
189 // guarantee exists so it's feasible to implement the TA part of an Identity
190 // Credential HAL implementation where the TA uses a 32-bit word to indicate
191 // which profiles are authorized.
192 for (const SecureAccessControlProfile& profile : allProfiles) {
193 if (profile.id < 0 || profile.id >= 32) {
194 return Status::fromServiceSpecificError(
195 ICredentialStore::ERROR_GENERIC,
196 "Invalid accessProfileId in profile (must be between 0 and 31)");
197 }
198 }
199
200 vector<bool> includeProfile(32);
201
202 for (const RequestNamespaceParcel& rns : requestNamespaces) {
203 size_t numEntriesInNsToRequest = 0;
204 for (const RequestEntryParcel& rep : rns.entries) {
205 if (data_->hasEntryData(rns.namespaceName, rep.name)) {
206 numEntriesInNsToRequest++;
207 }
208
209 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
210 if (data) {
211 for (int32_t id : data.value().accessControlProfileIds) {
212 if (id < 0 || id >= 32) {
213 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
214 << rns.namespaceName << ": " << rep.name;
215 return Status::fromServiceSpecificError(
216 ICredentialStore::ERROR_GENERIC,
217 "Invalid accessProfileId in entry (must be between 0 and 31)");
218 }
219 includeProfile[id] = true;
220 }
221 }
222 }
223 requestCounts.push_back(numEntriesInNsToRequest);
224 }
225
226 // Now that we know which profiles are needed, send only those to the
227 // HAL.
228 vector<SecureAccessControlProfile> selectedProfiles;
229 for (size_t n = 0; n < allProfiles.size(); n++) {
230 if (includeProfile[allProfiles[n].id]) {
231 selectedProfiles.push_back(allProfiles[n]);
232 }
233 }
234
235 // Calculate the highest [1] non-zero timeout and if user-auth is needed
236 // ... we need this to select an appropriate authToken.
237 //
238 // [1] : Why do we request the highest timeout and not the lowest? Well, we
239 // return partial results in getEntries e.g. if some data elements
240 // fail to authorize we'll still return the ones that did not fail. So
241 // e.g. consider data elements A and B where A has an ACP with 60
242 // seconds and B has an ACP with 3600 seconds. In this case we'll be
243 // fine with getting an authToken for e.g. 2400 seconds which would
244 // mean returning only B.
245 //
246 bool userAuthNeeded = false;
247 unsigned int authTokenMaxAgeMillis = 0;
248 for (auto& profile : selectedProfiles) {
249 if (profile.userAuthenticationRequired) {
250 userAuthNeeded = true;
251 if (profile.timeoutMillis > 0) {
252 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
253 authTokenMaxAgeMillis = profile.timeoutMillis;
254 }
255 }
256 }
257 }
258
259 // If requesting a challenge-based authToken the idea is that authentication
260 // happens as part of the transaction. As such, authTokenMaxAgeMillis should
261 // be nearly zero. We'll use 10 seconds for this.
262 if (userAuthNeeded && selectedChallenge_ != 0) {
263 authTokenMaxAgeMillis = 10 * 1000;
264 }
265
266 // Reset tokens and only get them if they're actually needed, e.g. if user authentication
267 // is needed in any of the access control profiles for data items being requested.
268 //
269 AidlHardwareAuthToken aidlAuthToken;
270 AidlVerificationToken aidlVerificationToken;
271 aidlAuthToken.challenge = 0;
272 aidlAuthToken.userId = 0;
273 aidlAuthToken.authenticatorId = 0;
274 aidlAuthToken.authenticatorType =
275 ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
276 aidlAuthToken.timestamp.milliSeconds = 0;
277 aidlAuthToken.mac.clear();
278 aidlVerificationToken.challenge = 0;
279 aidlVerificationToken.timestamp.milliSeconds = 0;
280 aidlVerificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
281 aidlVerificationToken.mac.clear();
282 if (userAuthNeeded) {
283 vector<uint8_t> authTokenBytes;
284 vector<uint8_t> verificationTokenBytes;
285 if (!getTokensFromKeystore(selectedChallenge_, data_->getSecureUserId(),
286 authTokenMaxAgeMillis, authTokenBytes, verificationTokenBytes)) {
287 LOG(ERROR) << "Error getting tokens from keystore";
288 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
289 "Error getting tokens from keystore");
290 }
291
292 // It's entirely possible getTokensFromKeystore() succeeded but didn't
293 // return any tokens (in which case the returned byte-vectors are
294 // empty). For example, this can happen if no auth token is available
295 // which satifies e.g. |authTokenMaxAgeMillis|.
296 //
297 if (authTokenBytes.size() > 0) {
298 HardwareAuthToken authToken =
299 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(authTokenBytes);
300 // Convert from HIDL to AIDL...
301 aidlAuthToken.challenge = int64_t(authToken.challenge);
302 aidlAuthToken.userId = int64_t(authToken.userId);
303 aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
304 aidlAuthToken.authenticatorType =
305 ::android::hardware::keymaster::HardwareAuthenticatorType(
306 int32_t(authToken.authenticatorType));
307 aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
308 aidlAuthToken.mac = authToken.mac;
309 }
310
311 if (verificationTokenBytes.size() > 0) {
312 optional<VerificationToken> token =
313 android::hardware::keymaster::V4_0::support::deserializeVerificationToken(
314 verificationTokenBytes);
315 if (!token) {
316 LOG(ERROR) << "Error deserializing verification token";
317 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
318 "Error deserializing verification token");
319 }
320 aidlVerificationToken.challenge = token->challenge;
321 aidlVerificationToken.timestamp.milliSeconds = token->timestamp;
322 aidlVerificationToken.securityLevel =
323 ::android::hardware::keymaster::SecurityLevel(token->securityLevel);
324 aidlVerificationToken.mac = token->mac;
325 }
326 }
327
328 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
329 // the Java layer. So we could end up with no previously selected auth key and we may
330 // need one.
331 const AuthKeyData* authKey = selectedAuthKey_;
332 if (sessionTranscript.size() > 0) {
333 if (authKey == nullptr) {
334 authKey = data_->selectAuthKey(allowUsingExhaustedKeys);
335 if (authKey == nullptr) {
336 return Status::fromServiceSpecificError(
337 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
338 "No suitable authentication key available");
339 }
340 }
341 }
342 vector<uint8_t> signingKeyBlob;
343 if (authKey != nullptr) {
344 signingKeyBlob = authKey->keyBlob;
345 }
346
347 // Pass the HAL enough information to allow calculating the size of
348 // DeviceNameSpaces ahead of time.
349 vector<RequestNamespace> halRequestNamespaces;
350 for (const RequestNamespaceParcel& rns : requestNamespaces) {
351 RequestNamespace ns;
352 ns.namespaceName = rns.namespaceName;
353 for (const RequestEntryParcel& rep : rns.entries) {
354 optional<EntryData> entryData = data_->getEntryData(rns.namespaceName, rep.name);
355 if (entryData) {
356 RequestDataItem di;
357 di.name = rep.name;
358 di.size = entryData.value().size;
359 di.accessControlProfileIds = entryData.value().accessControlProfileIds;
360 ns.items.push_back(di);
361 }
362 }
363 if (ns.items.size() > 0) {
364 halRequestNamespaces.push_back(ns);
365 }
366 }
367 // This is not catastrophic, we might be dealing with a version 1 implementation which
368 // doesn't have this method.
369 Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces);
370 if (!status.isOk()) {
371 LOG(INFO) << "Failed setting expected requested namespaces, assuming V1 HAL "
372 << "and continuing";
373 }
374
375 // Pass the verification token. Failure is OK, this method isn't in the V1 HAL.
376 status = halBinder_->setVerificationToken(aidlVerificationToken);
377 if (!status.isOk()) {
378 LOG(INFO) << "Failed setting verification token, assuming V1 HAL "
379 << "and continuing";
380 }
381
382 status =
383 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
384 sessionTranscript, readerSignature, requestCounts);
385 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
386 int code = status.serviceSpecificErrorCode();
387 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
388 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
389 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
390 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
391 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
392 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
393 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
394 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
395 }
396 }
397 if (!status.isOk()) {
398 return halStatusToGenericError(status);
399 }
400
401 for (const RequestNamespaceParcel& rns : requestNamespaces) {
402 ResultNamespaceParcel resultNamespaceParcel;
403 resultNamespaceParcel.namespaceName = rns.namespaceName;
404
405 for (const RequestEntryParcel& rep : rns.entries) {
406 ResultEntryParcel resultEntryParcel;
407 resultEntryParcel.name = rep.name;
408
409 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
410 if (!data) {
411 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
412 resultNamespaceParcel.entries.push_back(resultEntryParcel);
413 continue;
414 }
415
416 status =
417 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, data.value().size,
418 data.value().accessControlProfileIds);
419 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
420 int code = status.serviceSpecificErrorCode();
421 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
422 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
423 resultNamespaceParcel.entries.push_back(resultEntryParcel);
424 continue;
425 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
426 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
427 resultNamespaceParcel.entries.push_back(resultEntryParcel);
428 continue;
429 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
430 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
431 resultNamespaceParcel.entries.push_back(resultEntryParcel);
432 continue;
433 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
434 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
435 resultNamespaceParcel.entries.push_back(resultEntryParcel);
436 continue;
437 }
438 }
439 if (!status.isOk()) {
440 return halStatusToGenericError(status);
441 }
442
443 vector<uint8_t> value;
444 for (const auto& encryptedChunk : data.value().encryptedChunks) {
445 vector<uint8_t> chunk;
446 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
447 if (!status.isOk()) {
448 return halStatusToGenericError(status);
449 }
450 value.insert(value.end(), chunk.begin(), chunk.end());
451 }
452
453 resultEntryParcel.status = STATUS_OK;
454 resultEntryParcel.value = value;
455 resultNamespaceParcel.entries.push_back(resultEntryParcel);
456 }
457 ret.resultNamespaces.push_back(resultNamespaceParcel);
458 }
459
460 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
461 if (!status.isOk()) {
462 return halStatusToGenericError(status);
463 }
464 if (authKey != nullptr) {
465 ret.staticAuthenticationData = authKey->staticAuthenticationData;
466 }
467
468 // Ensure useCount is updated on disk.
469 if (authKey != nullptr) {
470 if (!data_->saveToDisk()) {
471 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
472 "Error saving data");
473 }
474 }
475
476 *_aidl_return = ret;
477 return Status::ok();
478 }
479
deleteCredential(vector<uint8_t> * _aidl_return)480 Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
481 vector<uint8_t> proofOfDeletionSignature;
482 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
483 if (!status.isOk()) {
484 return halStatusToGenericError(status);
485 }
486 if (!data_->deleteCredential()) {
487 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
488 "Error deleting credential data on disk");
489 }
490 *_aidl_return = proofOfDeletionSignature;
491 return Status::ok();
492 }
493
createEphemeralKeyPair(vector<uint8_t> * _aidl_return)494 Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
495 vector<uint8_t> keyPair;
496 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
497 if (!status.isOk()) {
498 return halStatusToGenericError(status);
499 }
500
501 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
502 "ephemeralKey", // Alias for key
503 "0", // Serial, as a decimal number
504 "Credstore", // Issuer
505 "Ephemeral Key", // Subject
506 0, // Validity Not Before
507 24 * 60 * 60); // Validity Not After
508 if (!pkcs12Bytes) {
509 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
510 "Error creating PKCS#12 structure for key pair");
511 }
512 *_aidl_return = pkcs12Bytes.value();
513 return Status::ok();
514 }
515
setReaderEphemeralPublicKey(const vector<uint8_t> & publicKey)516 Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
517 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
518 if (!status.isOk()) {
519 return halStatusToGenericError(status);
520 }
521 return Status::ok();
522 }
523
setAvailableAuthenticationKeys(int32_t keyCount,int32_t maxUsesPerKey)524 Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
525 data_->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
526 if (!data_->saveToDisk()) {
527 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
528 "Error saving data");
529 }
530 return Status::ok();
531 }
532
getAuthKeysNeedingCertification(vector<AuthKeyParcel> * _aidl_return)533 Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
534 optional<vector<vector<uint8_t>>> keysNeedingCert =
535 data_->getAuthKeysNeedingCertification(halBinder_);
536 if (!keysNeedingCert) {
537 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
538 "Error getting auth keys neededing certification");
539 }
540 vector<AuthKeyParcel> authKeyParcels;
541 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
542 AuthKeyParcel authKeyParcel;
543 authKeyParcel.x509cert = key;
544 authKeyParcels.push_back(authKeyParcel);
545 }
546 if (!data_->saveToDisk()) {
547 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
548 "Error saving data");
549 }
550 *_aidl_return = authKeyParcels;
551 return Status::ok();
552 }
553
storeStaticAuthenticationData(const AuthKeyParcel & authenticationKey,const vector<uint8_t> & staticAuthData)554 Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
555 const vector<uint8_t>& staticAuthData) {
556 if (!data_->storeStaticAuthenticationData(authenticationKey.x509cert, staticAuthData)) {
557 return Status::fromServiceSpecificError(
558 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
559 "Error finding authentication key to store static "
560 "authentication data for");
561 }
562 if (!data_->saveToDisk()) {
563 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
564 "Error saving data");
565 }
566 return Status::ok();
567 }
568
getAuthenticationDataUsageCount(vector<int32_t> * _aidl_return)569 Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
570 const vector<AuthKeyData>& authKeyDatas = data_->getAuthKeyDatas();
571 vector<int32_t> ret;
572 for (const AuthKeyData& authKeyData : authKeyDatas) {
573 ret.push_back(authKeyData.useCount);
574 }
575 *_aidl_return = ret;
576 return Status::ok();
577 }
578
579 } // namespace identity
580 } // namespace security
581 } // namespace android
582