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 "credstore"
18
19 #include <chrono>
20
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <android-base/logging.h>
28 #include <android-base/stringprintf.h>
29
30 #include <cppbor.h>
31 #include <cppbor_parse.h>
32
33 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
34
35 #include "CredentialData.h"
36 #include "Util.h"
37
38 namespace android {
39 namespace security {
40 namespace identity {
41
42 using std::optional;
43
calculateCredentialFileName(const string & dataPath,uid_t ownerUid,const string & name)44 string CredentialData::calculateCredentialFileName(const string& dataPath, uid_t ownerUid,
45 const string& name) {
46 return android::base::StringPrintf(
47 "%s/%d-%s", dataPath.c_str(), (int)ownerUid,
48 android::hardware::identity::support::encodeHex(name).c_str());
49 }
50
CredentialData(const string & dataPath,uid_t ownerUid,const string & name)51 CredentialData::CredentialData(const string& dataPath, uid_t ownerUid, const string& name)
52 : dataPath_(dataPath), ownerUid_(ownerUid), name_(name), secureUserId_(0) {
53 fileName_ = calculateCredentialFileName(dataPath_, ownerUid_, name_);
54 }
55
setSecureUserId(int64_t secureUserId)56 void CredentialData::setSecureUserId(int64_t secureUserId) {
57 secureUserId_ = secureUserId;
58 }
59
setCredentialData(const vector<uint8_t> & credentialData)60 void CredentialData::setCredentialData(const vector<uint8_t>& credentialData) {
61 credentialData_ = credentialData;
62 }
63
setAttestationCertificate(const vector<uint8_t> & attestationCertificate)64 void CredentialData::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
65 attestationCertificate_ = attestationCertificate;
66 }
67
addSecureAccessControlProfile(const SecureAccessControlProfile & secureAccessControlProfile)68 void CredentialData::addSecureAccessControlProfile(
69 const SecureAccessControlProfile& secureAccessControlProfile) {
70 secureAccessControlProfiles_.push_back(secureAccessControlProfile);
71 }
72
addEntryData(const string & namespaceName,const string & entryName,const EntryData & data)73 void CredentialData::addEntryData(const string& namespaceName, const string& entryName,
74 const EntryData& data) {
75 idToEncryptedChunks_[namespaceName + ":" + entryName] = data;
76 }
77
saveToDisk() const78 bool CredentialData::saveToDisk() const {
79 cppbor::Map map;
80
81 map.add("secureUserId", secureUserId_);
82
83 map.add("credentialData", credentialData_);
84
85 map.add("attestationCertificate", attestationCertificate_);
86
87 cppbor::Array sacpArray;
88 for (const SecureAccessControlProfile& sacp : secureAccessControlProfiles_) {
89 cppbor::Array array;
90 array.add(sacp.id);
91 array.add(sacp.readerCertificate.encodedCertificate);
92 array.add(sacp.userAuthenticationRequired);
93 array.add(sacp.timeoutMillis);
94 array.add(sacp.secureUserId);
95 vector<uint8_t> mac = sacp.mac;
96 array.add(mac);
97 sacpArray.add(std::move(array));
98 }
99 map.add("secureAccessControlProfiles", std::move(sacpArray));
100
101 cppbor::Map encryptedBlobsMap;
102 for (auto const& [nsAndName, entryData] : idToEncryptedChunks_) {
103 cppbor::Array encryptedChunkArray;
104 for (const vector<uint8_t>& encryptedChunk : entryData.encryptedChunks) {
105 encryptedChunkArray.add(encryptedChunk);
106 }
107 cppbor::Array entryDataArray;
108 entryDataArray.add(entryData.size);
109 cppbor::Array idsArray;
110 for (int32_t id : entryData.accessControlProfileIds) {
111 idsArray.add(id);
112 }
113 entryDataArray.add(std::move(idsArray));
114 entryDataArray.add(std::move(encryptedChunkArray));
115 encryptedBlobsMap.add(nsAndName, std::move(entryDataArray));
116 }
117 map.add("entryData", std::move(encryptedBlobsMap));
118 map.add("authKeyCount", keyCount_);
119 map.add("maxUsesPerAuthKey", maxUsesPerKey_);
120
121 cppbor::Array authKeyDatasArray;
122 for (const AuthKeyData& data : authKeyDatas_) {
123 cppbor::Array array;
124 // Fields 0-6 was in the original version in Android 11
125 array.add(data.certificate);
126 array.add(data.keyBlob);
127 array.add(data.staticAuthenticationData);
128 array.add(data.pendingCertificate);
129 array.add(data.pendingKeyBlob);
130 array.add(data.useCount);
131 // Field 7 was added in Android 12
132 array.add(data.expirationDateMillisSinceEpoch);
133 authKeyDatasArray.add(std::move(array));
134 }
135 map.add("authKeyData", std::move(authKeyDatasArray));
136
137 vector<uint8_t> credentialData = map.encode();
138
139 return fileSetContents(fileName_, credentialData);
140 }
141
parseSacp(const cppbor::Item & item)142 optional<SecureAccessControlProfile> parseSacp(const cppbor::Item& item) {
143 const cppbor::Array* array = item.asArray();
144 if (array == nullptr || array->size() < 6) {
145 LOG(ERROR) << "The SACP CBOR is not an array with at least six elements (size="
146 << (array != nullptr ? array->size() : -1) << ")";
147 return {};
148 }
149 const cppbor::Int* itemId = ((*array)[0])->asInt();
150 const cppbor::Bstr* itemReaderCertificate = ((*array)[1])->asBstr();
151 const cppbor::Simple* simple = ((*array)[2])->asSimple();
152 const cppbor::Bool* itemUserAuthenticationRequired =
153 (simple != nullptr ? (simple->asBool()) : nullptr);
154 const cppbor::Int* itemTimeoutMillis = ((*array)[3])->asInt();
155 const cppbor::Int* itesecureUserId_ = ((*array)[4])->asInt();
156 const cppbor::Bstr* itemMac = ((*array)[5])->asBstr();
157 if (itemId == nullptr || itemReaderCertificate == nullptr ||
158 itemUserAuthenticationRequired == nullptr || itemTimeoutMillis == nullptr ||
159 itesecureUserId_ == nullptr || itemMac == nullptr) {
160 LOG(ERROR) << "One or more items SACP array in CBOR is of wrong type";
161 return {};
162 }
163 SecureAccessControlProfile sacp;
164 sacp.id = itemId->value();
165 sacp.readerCertificate.encodedCertificate = itemReaderCertificate->value();
166 sacp.userAuthenticationRequired = itemUserAuthenticationRequired->value();
167 sacp.timeoutMillis = itemTimeoutMillis->value();
168 sacp.secureUserId = itesecureUserId_->value();
169 sacp.mac = itemMac->value();
170 return sacp;
171 }
172
parseAuthKeyData(const cppbor::Item & item)173 optional<AuthKeyData> parseAuthKeyData(const cppbor::Item& item) {
174 const cppbor::Array* array = item.asArray();
175 if (array == nullptr || array->size() < 6) {
176 LOG(ERROR) << "The AuthKeyData CBOR is not an array with at least six elements";
177 return {};
178 }
179 const cppbor::Bstr* itemCertificate = ((*array)[0])->asBstr();
180 const cppbor::Bstr* itemKeyBlob = ((*array)[1])->asBstr();
181 const cppbor::Bstr* itemStaticAuthenticationData = ((*array)[2])->asBstr();
182 const cppbor::Bstr* itemPendingCertificate = ((*array)[3])->asBstr();
183 const cppbor::Bstr* itemPendingKeyBlob = ((*array)[4])->asBstr();
184 const cppbor::Int* itemUseCount = ((*array)[5])->asInt();
185 if (itemCertificate == nullptr || itemKeyBlob == nullptr ||
186 itemStaticAuthenticationData == nullptr || itemPendingCertificate == nullptr ||
187 itemPendingKeyBlob == nullptr || itemUseCount == nullptr) {
188 LOG(ERROR) << "One or more items in AuthKeyData array in CBOR is of wrong type";
189 return {};
190 }
191 // expirationDateMillisSinceEpoch was added as the 7th element for Android 12. If not
192 // present, default to longest possible expiration date.
193 int64_t expirationDateMillisSinceEpoch = INT64_MAX;
194 if (array->size() >= 7) {
195 const cppbor::Int* itemExpirationDateMillisSinceEpoch = ((*array)[6])->asInt();
196 expirationDateMillisSinceEpoch = itemExpirationDateMillisSinceEpoch->value();
197 }
198 AuthKeyData authKeyData;
199 authKeyData.certificate = itemCertificate->value();
200 authKeyData.keyBlob = itemKeyBlob->value();
201 authKeyData.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
202 authKeyData.staticAuthenticationData = itemStaticAuthenticationData->value();
203 authKeyData.pendingCertificate = itemPendingCertificate->value();
204 authKeyData.pendingKeyBlob = itemPendingKeyBlob->value();
205 authKeyData.useCount = itemUseCount->value();
206 return authKeyData;
207 }
208
parseAccessControlProfileIds(const cppbor::Item & item)209 vector<int32_t> parseAccessControlProfileIds(const cppbor::Item& item) {
210 const cppbor::Array* array = item.asArray();
211 if (array == nullptr) {
212 LOG(ERROR) << "The accessControlProfileIds member is not an array";
213 return {};
214 }
215
216 vector<int32_t> accessControlProfileIds;
217 for (size_t n = 0; n < array->size(); n++) {
218 const cppbor::Int* itemInt = ((*array)[n])->asInt();
219 if (itemInt == nullptr) {
220 LOG(ERROR) << "An item in the accessControlProfileIds array is not a bstr";
221 return {};
222 }
223 accessControlProfileIds.push_back(itemInt->value());
224 }
225 return accessControlProfileIds;
226 }
227
parseEncryptedChunks(const cppbor::Item & item)228 optional<vector<vector<uint8_t>>> parseEncryptedChunks(const cppbor::Item& item) {
229 const cppbor::Array* array = item.asArray();
230 if (array == nullptr) {
231 LOG(ERROR) << "The encryptedChunks member is not an array";
232 return {};
233 }
234
235 vector<vector<uint8_t>> encryptedChunks;
236 for (size_t n = 0; n < array->size(); n++) {
237 const cppbor::Bstr* itemBstr = ((*array)[n])->asBstr();
238 if (itemBstr == nullptr) {
239 LOG(ERROR) << "An item in the encryptedChunks array is not a bstr";
240 return {};
241 }
242 encryptedChunks.push_back(itemBstr->value());
243 }
244 return encryptedChunks;
245 }
246
loadFromDisk()247 bool CredentialData::loadFromDisk() {
248 // Reset all data.
249 credentialData_.clear();
250 attestationCertificate_.clear();
251 secureAccessControlProfiles_.clear();
252 idToEncryptedChunks_.clear();
253 authKeyDatas_.clear();
254 keyCount_ = 0;
255 maxUsesPerKey_ = 1;
256
257 optional<vector<uint8_t>> data = fileGetContents(fileName_);
258 if (!data) {
259 LOG(ERROR) << "Error loading data";
260 return false;
261 }
262
263 auto [item, _ /* newPos */, message] = cppbor::parse(data.value());
264 if (item == nullptr) {
265 LOG(ERROR) << "Data loaded from " << fileName_ << " is not valid CBOR: " << message;
266 return false;
267 }
268
269 const cppbor::Map* map = item->asMap();
270 if (map == nullptr) {
271 LOG(ERROR) << "Top-level item is not a map";
272 return false;
273 }
274
275 for (size_t n = 0; n < map->size(); n++) {
276 auto& [keyItem, valueItem] = (*map)[n];
277 const cppbor::Tstr* tstr = keyItem->asTstr();
278 if (tstr == nullptr) {
279 LOG(ERROR) << "Key item in top-level map is not a tstr";
280 return false;
281 }
282 const string& key = tstr->value();
283
284 if (key == "secureUserId") {
285 const cppbor::Int* number = valueItem->asInt();
286 if (number == nullptr) {
287 LOG(ERROR) << "Value for secureUserId is not a number";
288 return false;
289 }
290 secureUserId_ = number->value();
291 } else if (key == "credentialData") {
292 const cppbor::Bstr* valueBstr = valueItem->asBstr();
293 if (valueBstr == nullptr) {
294 LOG(ERROR) << "Value for credentialData is not a bstr";
295 return false;
296 }
297 credentialData_ = valueBstr->value();
298 } else if (key == "attestationCertificate") {
299 const cppbor::Bstr* valueBstr = valueItem->asBstr();
300 if (valueBstr == nullptr) {
301 LOG(ERROR) << "Value for attestationCertificate is not a bstr";
302 return false;
303 }
304 attestationCertificate_ = valueBstr->value();
305 } else if (key == "secureAccessControlProfiles") {
306 const cppbor::Array* array = valueItem->asArray();
307 if (array == nullptr) {
308 LOG(ERROR) << "Value for attestationCertificate is not an array";
309 return false;
310 }
311 for (size_t m = 0; m < array->size(); m++) {
312 const std::unique_ptr<cppbor::Item>& item = (*array)[m];
313 optional<SecureAccessControlProfile> sacp = parseSacp(*item);
314 if (!sacp) {
315 LOG(ERROR) << "Error parsing SecureAccessControlProfile";
316 return false;
317 }
318 secureAccessControlProfiles_.push_back(sacp.value());
319 }
320
321 } else if (key == "entryData") {
322 const cppbor::Map* map = valueItem->asMap();
323 if (map == nullptr) {
324 LOG(ERROR) << "Value for encryptedChunks is not an map";
325 return false;
326 }
327 for (size_t m = 0; m < map->size(); m++) {
328 auto& [ecKeyItem, ecValueItem] = (*map)[m];
329 const cppbor::Tstr* ecTstr = ecKeyItem->asTstr();
330 if (ecTstr == nullptr) {
331 LOG(ERROR) << "Key item in encryptedChunks map is not a tstr";
332 return false;
333 }
334 const string& ecId = ecTstr->value();
335
336 const cppbor::Array* ecEntryArrayItem = ecValueItem->asArray();
337 if (ecEntryArrayItem == nullptr || ecEntryArrayItem->size() < 3) {
338 LOG(ERROR) << "Value item in encryptedChunks map is an array with at least two "
339 "elements";
340 return false;
341 }
342 const cppbor::Int* ecEntrySizeItem = (*ecEntryArrayItem)[0]->asInt();
343 if (ecEntrySizeItem == nullptr) {
344 LOG(ERROR) << "Entry size not a number";
345 return false;
346 }
347 uint64_t entrySize = ecEntrySizeItem->value();
348
349 optional<vector<int32_t>> accessControlProfileIds =
350 parseAccessControlProfileIds(*(*ecEntryArrayItem)[1]);
351 if (!accessControlProfileIds) {
352 LOG(ERROR) << "Error parsing access control profile ids";
353 return false;
354 }
355
356 optional<vector<vector<uint8_t>>> encryptedChunks =
357 parseEncryptedChunks(*(*ecEntryArrayItem)[2]);
358 if (!encryptedChunks) {
359 LOG(ERROR) << "Error parsing encrypted chunks";
360 return false;
361 }
362
363 EntryData data;
364 data.size = entrySize;
365 data.accessControlProfileIds = accessControlProfileIds.value();
366 data.encryptedChunks = encryptedChunks.value();
367 idToEncryptedChunks_[ecId] = data;
368 }
369
370 } else if (key == "authKeyData") {
371 const cppbor::Array* array = valueItem->asArray();
372 if (array == nullptr) {
373 LOG(ERROR) << "Value for authData is not an array";
374 return false;
375 }
376 for (size_t m = 0; m < array->size(); m++) {
377 const std::unique_ptr<cppbor::Item>& item = (*array)[m];
378 optional<AuthKeyData> authKeyData = parseAuthKeyData(*item);
379 if (!authKeyData) {
380 LOG(ERROR) << "Error parsing AuthKeyData";
381 return false;
382 }
383 authKeyDatas_.push_back(authKeyData.value());
384 }
385
386 } else if (key == "authKeyCount") {
387 const cppbor::Int* number = valueItem->asInt();
388 if (number == nullptr) {
389 LOG(ERROR) << "Value for authKeyCount is not a number";
390 return false;
391 }
392 keyCount_ = number->value();
393
394 } else if (key == "maxUsesPerAuthKey") {
395 const cppbor::Int* number = valueItem->asInt();
396 if (number == nullptr) {
397 LOG(ERROR) << "Value for maxUsesPerAuthKey is not a number";
398 return false;
399 }
400 maxUsesPerKey_ = number->value();
401 }
402 }
403
404 if (credentialData_.size() == 0) {
405 LOG(ERROR) << "Missing credentialData";
406 return false;
407 }
408
409 if (attestationCertificate_.size() == 0) {
410 LOG(ERROR) << "Missing attestationCertificate";
411 return false;
412 }
413
414 if (size_t(keyCount_) != authKeyDatas_.size()) {
415 LOG(ERROR) << "keyCount_=" << keyCount_
416 << " != authKeyDatas_.size()=" << authKeyDatas_.size();
417 return false;
418 }
419
420 return true;
421 }
422
getCredentialData() const423 const vector<uint8_t>& CredentialData::getCredentialData() const {
424 return credentialData_;
425 }
426
getSecureUserId()427 int64_t CredentialData::getSecureUserId() {
428 return secureUserId_;
429 }
430
getAttestationCertificate() const431 const vector<uint8_t>& CredentialData::getAttestationCertificate() const {
432 return attestationCertificate_;
433 }
434
getSecureAccessControlProfiles() const435 const vector<SecureAccessControlProfile>& CredentialData::getSecureAccessControlProfiles() const {
436 return secureAccessControlProfiles_;
437 }
438
hasEntryData(const string & namespaceName,const string & entryName) const439 bool CredentialData::hasEntryData(const string& namespaceName, const string& entryName) const {
440 string id = namespaceName + ":" + entryName;
441 auto iter = idToEncryptedChunks_.find(id);
442 if (iter == idToEncryptedChunks_.end()) {
443 return false;
444 }
445 return true;
446 }
447
getEntryData(const string & namespaceName,const string & entryName) const448 optional<EntryData> CredentialData::getEntryData(const string& namespaceName,
449 const string& entryName) const {
450 string id = namespaceName + ":" + entryName;
451 auto iter = idToEncryptedChunks_.find(id);
452 if (iter == idToEncryptedChunks_.end()) {
453 return {};
454 }
455 return iter->second;
456 }
457
deleteCredential()458 bool CredentialData::deleteCredential() {
459 if (unlink(fileName_.c_str()) != 0) {
460 PLOG(ERROR) << "Error deleting " << fileName_;
461 return false;
462 }
463 return true;
464 }
465
credentialExists(const string & dataPath,uid_t ownerUid,const string & name)466 optional<bool> CredentialData::credentialExists(const string& dataPath, uid_t ownerUid,
467 const string& name) {
468 struct stat statbuf;
469 string filename = calculateCredentialFileName(dataPath, ownerUid, name);
470 if (stat(filename.c_str(), &statbuf) != 0) {
471 if (errno == ENOENT) {
472 return false;
473 }
474 PLOG(ERROR) << "Error getting information about " << filename;
475 return {};
476 }
477 return true;
478 }
479
480 // ---
481
setAvailableAuthenticationKeys(int keyCount,int maxUsesPerKey)482 void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
483 keyCount_ = keyCount;
484 maxUsesPerKey_ = maxUsesPerKey;
485
486 // If growing the number of auth keys (prevKeyCount < keyCount_ case) we'll add
487 // new AuthKeyData structs to |authKeyDatas_| and each struct will have empty |certificate|
488 // and |pendingCertificate| fields. Those will be filled out when the
489 // getAuthKeysNeedingCertification() is called.
490 //
491 // If shrinking, we'll just delete the AuthKeyData structs at the end. There's nothing
492 // else to do, the HAL doesn't need to know we're nuking these authentication keys.
493 //
494 // Therefore, in either case it's as simple as just resizing the vector.
495 authKeyDatas_.resize(keyCount_);
496 }
497
getAuthKeyDatas() const498 const vector<AuthKeyData>& CredentialData::getAuthKeyDatas() const {
499 return authKeyDatas_;
500 }
501
getAvailableAuthenticationKeys()502 pair<int /* keyCount */, int /*maxUsersPerKey */> CredentialData::getAvailableAuthenticationKeys() {
503 return std::make_pair(keyCount_, maxUsesPerKey_);
504 }
505
findAuthKey_(bool allowUsingExhaustedKeys,bool allowUsingExpiredKeys)506 AuthKeyData* CredentialData::findAuthKey_(bool allowUsingExhaustedKeys,
507 bool allowUsingExpiredKeys) {
508 AuthKeyData* candidate = nullptr;
509
510 int64_t nowMilliSeconds =
511 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
512
513 int n = 0;
514 for (AuthKeyData& data : authKeyDatas_) {
515 if (nowMilliSeconds > data.expirationDateMillisSinceEpoch) {
516 if (!allowUsingExpiredKeys) {
517 continue;
518 }
519 }
520 if (data.certificate.size() != 0) {
521 // Not expired, include in normal check
522 if (candidate == nullptr || data.useCount < candidate->useCount) {
523 candidate = &data;
524 }
525 }
526 n++;
527 }
528
529 if (candidate == nullptr) {
530 return nullptr;
531 }
532
533 if (candidate->useCount >= maxUsesPerKey_ && !allowUsingExhaustedKeys) {
534 return nullptr;
535 }
536
537 return candidate;
538 }
539
selectAuthKey(bool allowUsingExhaustedKeys,bool allowUsingExpiredKeys)540 const AuthKeyData* CredentialData::selectAuthKey(bool allowUsingExhaustedKeys,
541 bool allowUsingExpiredKeys) {
542 AuthKeyData* candidate;
543
544 // First try to find a un-expired key..
545 candidate = findAuthKey_(allowUsingExhaustedKeys, false);
546 if (candidate == nullptr) {
547 // That didn't work, there are no un-expired keys and we don't allow using expired keys.
548 if (!allowUsingExpiredKeys) {
549 return nullptr;
550 }
551
552 // See if there's an expired key then...
553 candidate = findAuthKey_(allowUsingExhaustedKeys, true);
554 if (candidate == nullptr) {
555 return nullptr;
556 }
557 }
558
559 candidate->useCount += 1;
560 return candidate;
561 }
562
563 optional<vector<vector<uint8_t>>>
getAuthKeysNeedingCertification(const sp<IIdentityCredential> & halBinder)564 CredentialData::getAuthKeysNeedingCertification(const sp<IIdentityCredential>& halBinder) {
565
566 vector<vector<uint8_t>> keysNeedingCert;
567
568 int64_t nowMilliSeconds =
569 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
570
571 for (AuthKeyData& data : authKeyDatas_) {
572 bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
573 bool keyBeyondExpirationDate = (nowMilliSeconds > data.expirationDateMillisSinceEpoch);
574 bool newKeyNeeded =
575 (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondExpirationDate;
576 bool certificationPending = (data.pendingCertificate.size() > 0);
577 if (newKeyNeeded && !certificationPending) {
578 vector<uint8_t> signingKeyBlob;
579 Certificate signingKeyCertificate;
580 if (!halBinder->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate)
581 .isOk()) {
582 LOG(ERROR) << "Error generating signing key-pair";
583 return {};
584 }
585 data.pendingCertificate = signingKeyCertificate.encodedCertificate;
586 data.pendingKeyBlob = signingKeyBlob;
587 certificationPending = true;
588 }
589
590 if (certificationPending) {
591 keysNeedingCert.push_back(data.pendingCertificate);
592 }
593 }
594 return keysNeedingCert;
595 }
596
storeStaticAuthenticationData(const vector<uint8_t> & authenticationKey,int64_t expirationDateMillisSinceEpoch,const vector<uint8_t> & staticAuthData)597 bool CredentialData::storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
598 int64_t expirationDateMillisSinceEpoch,
599 const vector<uint8_t>& staticAuthData) {
600 for (AuthKeyData& data : authKeyDatas_) {
601 if (data.pendingCertificate == authenticationKey) {
602 data.certificate = data.pendingCertificate;
603 data.keyBlob = data.pendingKeyBlob;
604 data.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
605 data.staticAuthenticationData = staticAuthData;
606 data.pendingCertificate.clear();
607 data.pendingKeyBlob.clear();
608 data.useCount = 0;
609 return true;
610 }
611 }
612 return false;
613 }
614
615 } // namespace identity
616 } // namespace security
617 } // namespace android
618