blob: 2189f909c67b6d36b67eaf1b3012447480da7465 [file] [log] [blame]
David Zeuthenab3e5652019-10-28 13:32:48 -04001/*
2 * Copyright (c) 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
David Zeuthen62d43bf2021-03-31 10:41:27 -040017#define LOG_TAG "credstore"
David Zeuthenab3e5652019-10-28 13:32:48 -040018
David Zeuthen472e6c82020-10-16 11:50:13 -040019#include <chrono>
20
David Zeuthenab3e5652019-10-28 13:32:48 -040021#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
38namespace android {
39namespace security {
40namespace identity {
41
David Zeuthenab3e5652019-10-28 13:32:48 -040042using std::optional;
43
44string 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
51CredentialData::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
56void CredentialData::setSecureUserId(int64_t secureUserId) {
57 secureUserId_ = secureUserId;
58}
59
60void CredentialData::setCredentialData(const vector<uint8_t>& credentialData) {
61 credentialData_ = credentialData;
62}
63
64void CredentialData::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
65 attestationCertificate_ = attestationCertificate;
66}
67
68void CredentialData::addSecureAccessControlProfile(
69 const SecureAccessControlProfile& secureAccessControlProfile) {
70 secureAccessControlProfiles_.push_back(secureAccessControlProfile);
71}
72
73void CredentialData::addEntryData(const string& namespaceName, const string& entryName,
74 const EntryData& data) {
75 idToEncryptedChunks_[namespaceName + ":" + entryName] = data;
76}
77
78bool 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);
David Zeuthena6f9fba2020-02-11 22:08:27 -050091 array.add(sacp.readerCertificate.encodedCertificate);
David Zeuthenab3e5652019-10-28 13:32:48 -040092 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;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500110 for (int32_t id : entryData.accessControlProfileIds) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400111 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;
David Zeuthen472e6c82020-10-16 11:50:13 -0400124 // Fields 0-6 was in the original version in Android 11
David Zeuthenab3e5652019-10-28 13:32:48 -0400125 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);
David Zeuthen472e6c82020-10-16 11:50:13 -0400131 // Field 7 was added in Android 12
132 array.add(data.expirationDateMillisSinceEpoch);
David Zeuthenab3e5652019-10-28 13:32:48 -0400133 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
142optional<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();
David Zeuthena6f9fba2020-02-11 22:08:27 -0500165 sacp.readerCertificate.encodedCertificate = itemReaderCertificate->value();
David Zeuthenab3e5652019-10-28 13:32:48 -0400166 sacp.userAuthenticationRequired = itemUserAuthenticationRequired->value();
167 sacp.timeoutMillis = itemTimeoutMillis->value();
168 sacp.secureUserId = itesecureUserId_->value();
169 sacp.mac = itemMac->value();
170 return sacp;
171}
172
173optional<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 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400191 // 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 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400198 AuthKeyData authKeyData;
199 authKeyData.certificate = itemCertificate->value();
200 authKeyData.keyBlob = itemKeyBlob->value();
David Zeuthen472e6c82020-10-16 11:50:13 -0400201 authKeyData.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
David Zeuthenab3e5652019-10-28 13:32:48 -0400202 authKeyData.staticAuthenticationData = itemStaticAuthenticationData->value();
203 authKeyData.pendingCertificate = itemPendingCertificate->value();
204 authKeyData.pendingKeyBlob = itemPendingKeyBlob->value();
205 authKeyData.useCount = itemUseCount->value();
206 return authKeyData;
207}
208
David Zeuthena6f9fba2020-02-11 22:08:27 -0500209vector<int32_t> parseAccessControlProfileIds(const cppbor::Item& item) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400210 const cppbor::Array* array = item.asArray();
211 if (array == nullptr) {
212 LOG(ERROR) << "The accessControlProfileIds member is not an array";
213 return {};
214 }
215
David Zeuthena6f9fba2020-02-11 22:08:27 -0500216 vector<int32_t> accessControlProfileIds;
David Zeuthenab3e5652019-10-28 13:32:48 -0400217 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
228optional<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
247bool CredentialData::loadFromDisk() {
David Zeuthenab3e5652019-10-28 13:32:48 -0400248 // 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++) {
Max Bires5bb33f42021-03-11 00:44:06 -0800276 auto& [keyItem, valueItem] = (*map)[n];
David Zeuthenab3e5652019-10-28 13:32:48 -0400277 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++) {
Max Bires5bb33f42021-03-11 00:44:06 -0800328 auto& [ecKeyItem, ecValueItem] = (*map)[m];
David Zeuthenab3e5652019-10-28 13:32:48 -0400329 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
David Zeuthena6f9fba2020-02-11 22:08:27 -0500349 optional<vector<int32_t>> accessControlProfileIds =
David Zeuthenab3e5652019-10-28 13:32:48 -0400350 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
David Zeuthena6f9fba2020-02-11 22:08:27 -0500404 if (credentialData_.size() == 0) {
405 LOG(ERROR) << "Missing credentialData";
406 return false;
407 }
408
409 if (attestationCertificate_.size() == 0) {
410 LOG(ERROR) << "Missing attestationCertificate";
David Zeuthenab3e5652019-10-28 13:32:48 -0400411 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
423const vector<uint8_t>& CredentialData::getCredentialData() const {
424 return credentialData_;
425}
426
427int64_t CredentialData::getSecureUserId() {
428 return secureUserId_;
429}
430
431const vector<uint8_t>& CredentialData::getAttestationCertificate() const {
432 return attestationCertificate_;
433}
434
435const vector<SecureAccessControlProfile>& CredentialData::getSecureAccessControlProfiles() const {
436 return secureAccessControlProfiles_;
437}
438
439bool 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
448optional<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
458bool CredentialData::deleteCredential() {
459 if (unlink(fileName_.c_str()) != 0) {
460 PLOG(ERROR) << "Error deleting " << fileName_;
461 return false;
462 }
463 return true;
464}
465
466optional<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
482void 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
498const vector<AuthKeyData>& CredentialData::getAuthKeyDatas() const {
499 return authKeyDatas_;
500}
501
David Zeuthen472e6c82020-10-16 11:50:13 -0400502pair<int /* keyCount */, int /*maxUsersPerKey */> CredentialData::getAvailableAuthenticationKeys() {
503 return std::make_pair(keyCount_, maxUsesPerKey_);
504}
505
506AuthKeyData* CredentialData::findAuthKey_(bool allowUsingExhaustedKeys,
507 bool allowUsingExpiredKeys) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400508 AuthKeyData* candidate = nullptr;
509
David Zeuthen472e6c82020-10-16 11:50:13 -0400510 int64_t nowMilliSeconds =
511 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
512
David Zeuthenab3e5652019-10-28 13:32:48 -0400513 int n = 0;
David Zeuthenab3e5652019-10-28 13:32:48 -0400514 for (AuthKeyData& data : authKeyDatas_) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400515 if (nowMilliSeconds > data.expirationDateMillisSinceEpoch) {
516 if (!allowUsingExpiredKeys) {
517 continue;
518 }
519 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400520 if (data.certificate.size() != 0) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400521 // Not expired, include in normal check
David Zeuthenab3e5652019-10-28 13:32:48 -0400522 if (candidate == nullptr || data.useCount < candidate->useCount) {
523 candidate = &data;
David Zeuthenab3e5652019-10-28 13:32:48 -0400524 }
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
David Zeuthen472e6c82020-10-16 11:50:13 -0400537 return candidate;
538}
539
540const AuthKeyData* CredentialData::selectAuthKey(bool allowUsingExhaustedKeys,
David Zeuthen045a2c82021-09-11 13:52:17 -0400541 bool allowUsingExpiredKeys,
542 bool incrementUsageCount) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400543 AuthKeyData* candidate;
544
545 // First try to find a un-expired key..
546 candidate = findAuthKey_(allowUsingExhaustedKeys, false);
547 if (candidate == nullptr) {
548 // That didn't work, there are no un-expired keys and we don't allow using expired keys.
549 if (!allowUsingExpiredKeys) {
550 return nullptr;
551 }
552
553 // See if there's an expired key then...
554 candidate = findAuthKey_(allowUsingExhaustedKeys, true);
555 if (candidate == nullptr) {
556 return nullptr;
557 }
558 }
559
David Zeuthen045a2c82021-09-11 13:52:17 -0400560 if (incrementUsageCount) {
561 candidate->useCount += 1;
562 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400563 return candidate;
564}
565
David Zeuthena6f9fba2020-02-11 22:08:27 -0500566optional<vector<vector<uint8_t>>>
567CredentialData::getAuthKeysNeedingCertification(const sp<IIdentityCredential>& halBinder) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400568
569 vector<vector<uint8_t>> keysNeedingCert;
570
David Zeuthen472e6c82020-10-16 11:50:13 -0400571 int64_t nowMilliSeconds =
572 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
573
David Zeuthenab3e5652019-10-28 13:32:48 -0400574 for (AuthKeyData& data : authKeyDatas_) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400575 bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
576 bool keyBeyondExpirationDate = (nowMilliSeconds > data.expirationDateMillisSinceEpoch);
577 bool newKeyNeeded =
578 (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondExpirationDate;
David Zeuthenab3e5652019-10-28 13:32:48 -0400579 bool certificationPending = (data.pendingCertificate.size() > 0);
580 if (newKeyNeeded && !certificationPending) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400581 vector<uint8_t> signingKeyBlob;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500582 Certificate signingKeyCertificate;
583 if (!halBinder->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate)
584 .isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400585 LOG(ERROR) << "Error generating signing key-pair";
586 return {};
587 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500588 data.pendingCertificate = signingKeyCertificate.encodedCertificate;
David Zeuthenab3e5652019-10-28 13:32:48 -0400589 data.pendingKeyBlob = signingKeyBlob;
590 certificationPending = true;
591 }
592
593 if (certificationPending) {
594 keysNeedingCert.push_back(data.pendingCertificate);
595 }
596 }
597 return keysNeedingCert;
598}
599
600bool CredentialData::storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
David Zeuthen472e6c82020-10-16 11:50:13 -0400601 int64_t expirationDateMillisSinceEpoch,
David Zeuthenab3e5652019-10-28 13:32:48 -0400602 const vector<uint8_t>& staticAuthData) {
603 for (AuthKeyData& data : authKeyDatas_) {
604 if (data.pendingCertificate == authenticationKey) {
605 data.certificate = data.pendingCertificate;
606 data.keyBlob = data.pendingKeyBlob;
David Zeuthen472e6c82020-10-16 11:50:13 -0400607 data.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
David Zeuthenab3e5652019-10-28 13:32:48 -0400608 data.staticAuthenticationData = staticAuthData;
609 data.pendingCertificate.clear();
610 data.pendingKeyBlob.clear();
611 data.useCount = 0;
612 return true;
613 }
614 }
615 return false;
616}
617
618} // namespace identity
619} // namespace security
620} // namespace android