blob: 1bf1527b767343acd6ff1615c8a3a39feab3a657 [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_);
David Zeuthenc239db42022-11-14 15:22:24 -0500120 map.add("minValidTimeMillis", minValidTimeMillis_);
David Zeuthenab3e5652019-10-28 13:32:48 -0400121
122 cppbor::Array authKeyDatasArray;
123 for (const AuthKeyData& data : authKeyDatas_) {
124 cppbor::Array array;
David Zeuthen472e6c82020-10-16 11:50:13 -0400125 // Fields 0-6 was in the original version in Android 11
David Zeuthenab3e5652019-10-28 13:32:48 -0400126 array.add(data.certificate);
127 array.add(data.keyBlob);
128 array.add(data.staticAuthenticationData);
129 array.add(data.pendingCertificate);
130 array.add(data.pendingKeyBlob);
131 array.add(data.useCount);
David Zeuthen472e6c82020-10-16 11:50:13 -0400132 // Field 7 was added in Android 12
133 array.add(data.expirationDateMillisSinceEpoch);
David Zeuthenab3e5652019-10-28 13:32:48 -0400134 authKeyDatasArray.add(std::move(array));
135 }
136 map.add("authKeyData", std::move(authKeyDatasArray));
137
138 vector<uint8_t> credentialData = map.encode();
139
140 return fileSetContents(fileName_, credentialData);
141}
142
143optional<SecureAccessControlProfile> parseSacp(const cppbor::Item& item) {
144 const cppbor::Array* array = item.asArray();
145 if (array == nullptr || array->size() < 6) {
146 LOG(ERROR) << "The SACP CBOR is not an array with at least six elements (size="
147 << (array != nullptr ? array->size() : -1) << ")";
148 return {};
149 }
150 const cppbor::Int* itemId = ((*array)[0])->asInt();
151 const cppbor::Bstr* itemReaderCertificate = ((*array)[1])->asBstr();
152 const cppbor::Simple* simple = ((*array)[2])->asSimple();
153 const cppbor::Bool* itemUserAuthenticationRequired =
154 (simple != nullptr ? (simple->asBool()) : nullptr);
155 const cppbor::Int* itemTimeoutMillis = ((*array)[3])->asInt();
156 const cppbor::Int* itesecureUserId_ = ((*array)[4])->asInt();
157 const cppbor::Bstr* itemMac = ((*array)[5])->asBstr();
158 if (itemId == nullptr || itemReaderCertificate == nullptr ||
159 itemUserAuthenticationRequired == nullptr || itemTimeoutMillis == nullptr ||
160 itesecureUserId_ == nullptr || itemMac == nullptr) {
161 LOG(ERROR) << "One or more items SACP array in CBOR is of wrong type";
162 return {};
163 }
164 SecureAccessControlProfile sacp;
165 sacp.id = itemId->value();
David Zeuthena6f9fba2020-02-11 22:08:27 -0500166 sacp.readerCertificate.encodedCertificate = itemReaderCertificate->value();
David Zeuthenab3e5652019-10-28 13:32:48 -0400167 sacp.userAuthenticationRequired = itemUserAuthenticationRequired->value();
168 sacp.timeoutMillis = itemTimeoutMillis->value();
169 sacp.secureUserId = itesecureUserId_->value();
170 sacp.mac = itemMac->value();
171 return sacp;
172}
173
174optional<AuthKeyData> parseAuthKeyData(const cppbor::Item& item) {
175 const cppbor::Array* array = item.asArray();
176 if (array == nullptr || array->size() < 6) {
177 LOG(ERROR) << "The AuthKeyData CBOR is not an array with at least six elements";
178 return {};
179 }
180 const cppbor::Bstr* itemCertificate = ((*array)[0])->asBstr();
181 const cppbor::Bstr* itemKeyBlob = ((*array)[1])->asBstr();
182 const cppbor::Bstr* itemStaticAuthenticationData = ((*array)[2])->asBstr();
183 const cppbor::Bstr* itemPendingCertificate = ((*array)[3])->asBstr();
184 const cppbor::Bstr* itemPendingKeyBlob = ((*array)[4])->asBstr();
185 const cppbor::Int* itemUseCount = ((*array)[5])->asInt();
186 if (itemCertificate == nullptr || itemKeyBlob == nullptr ||
187 itemStaticAuthenticationData == nullptr || itemPendingCertificate == nullptr ||
188 itemPendingKeyBlob == nullptr || itemUseCount == nullptr) {
189 LOG(ERROR) << "One or more items in AuthKeyData array in CBOR is of wrong type";
190 return {};
191 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400192 // expirationDateMillisSinceEpoch was added as the 7th element for Android 12. If not
193 // present, default to longest possible expiration date.
194 int64_t expirationDateMillisSinceEpoch = INT64_MAX;
195 if (array->size() >= 7) {
196 const cppbor::Int* itemExpirationDateMillisSinceEpoch = ((*array)[6])->asInt();
197 expirationDateMillisSinceEpoch = itemExpirationDateMillisSinceEpoch->value();
198 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400199 AuthKeyData authKeyData;
200 authKeyData.certificate = itemCertificate->value();
201 authKeyData.keyBlob = itemKeyBlob->value();
David Zeuthen472e6c82020-10-16 11:50:13 -0400202 authKeyData.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
David Zeuthenab3e5652019-10-28 13:32:48 -0400203 authKeyData.staticAuthenticationData = itemStaticAuthenticationData->value();
204 authKeyData.pendingCertificate = itemPendingCertificate->value();
205 authKeyData.pendingKeyBlob = itemPendingKeyBlob->value();
206 authKeyData.useCount = itemUseCount->value();
207 return authKeyData;
208}
209
David Zeuthena6f9fba2020-02-11 22:08:27 -0500210vector<int32_t> parseAccessControlProfileIds(const cppbor::Item& item) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400211 const cppbor::Array* array = item.asArray();
212 if (array == nullptr) {
213 LOG(ERROR) << "The accessControlProfileIds member is not an array";
214 return {};
215 }
216
David Zeuthena6f9fba2020-02-11 22:08:27 -0500217 vector<int32_t> accessControlProfileIds;
David Zeuthenab3e5652019-10-28 13:32:48 -0400218 for (size_t n = 0; n < array->size(); n++) {
219 const cppbor::Int* itemInt = ((*array)[n])->asInt();
220 if (itemInt == nullptr) {
221 LOG(ERROR) << "An item in the accessControlProfileIds array is not a bstr";
222 return {};
223 }
224 accessControlProfileIds.push_back(itemInt->value());
225 }
226 return accessControlProfileIds;
227}
228
229optional<vector<vector<uint8_t>>> parseEncryptedChunks(const cppbor::Item& item) {
230 const cppbor::Array* array = item.asArray();
231 if (array == nullptr) {
232 LOG(ERROR) << "The encryptedChunks member is not an array";
233 return {};
234 }
235
236 vector<vector<uint8_t>> encryptedChunks;
237 for (size_t n = 0; n < array->size(); n++) {
238 const cppbor::Bstr* itemBstr = ((*array)[n])->asBstr();
239 if (itemBstr == nullptr) {
240 LOG(ERROR) << "An item in the encryptedChunks array is not a bstr";
241 return {};
242 }
243 encryptedChunks.push_back(itemBstr->value());
244 }
245 return encryptedChunks;
246}
247
248bool CredentialData::loadFromDisk() {
David Zeuthenab3e5652019-10-28 13:32:48 -0400249 // Reset all data.
250 credentialData_.clear();
251 attestationCertificate_.clear();
252 secureAccessControlProfiles_.clear();
253 idToEncryptedChunks_.clear();
254 authKeyDatas_.clear();
255 keyCount_ = 0;
256 maxUsesPerKey_ = 1;
David Zeuthenc239db42022-11-14 15:22:24 -0500257 minValidTimeMillis_ = 0;
David Zeuthenab3e5652019-10-28 13:32:48 -0400258
259 optional<vector<uint8_t>> data = fileGetContents(fileName_);
260 if (!data) {
261 LOG(ERROR) << "Error loading data";
262 return false;
263 }
264
265 auto [item, _ /* newPos */, message] = cppbor::parse(data.value());
266 if (item == nullptr) {
267 LOG(ERROR) << "Data loaded from " << fileName_ << " is not valid CBOR: " << message;
268 return false;
269 }
270
271 const cppbor::Map* map = item->asMap();
272 if (map == nullptr) {
273 LOG(ERROR) << "Top-level item is not a map";
274 return false;
275 }
276
277 for (size_t n = 0; n < map->size(); n++) {
Max Bires5bb33f42021-03-11 00:44:06 -0800278 auto& [keyItem, valueItem] = (*map)[n];
David Zeuthenab3e5652019-10-28 13:32:48 -0400279 const cppbor::Tstr* tstr = keyItem->asTstr();
280 if (tstr == nullptr) {
281 LOG(ERROR) << "Key item in top-level map is not a tstr";
282 return false;
283 }
284 const string& key = tstr->value();
285
286 if (key == "secureUserId") {
287 const cppbor::Int* number = valueItem->asInt();
288 if (number == nullptr) {
289 LOG(ERROR) << "Value for secureUserId is not a number";
290 return false;
291 }
292 secureUserId_ = number->value();
293 } else if (key == "credentialData") {
294 const cppbor::Bstr* valueBstr = valueItem->asBstr();
295 if (valueBstr == nullptr) {
296 LOG(ERROR) << "Value for credentialData is not a bstr";
297 return false;
298 }
299 credentialData_ = valueBstr->value();
300 } else if (key == "attestationCertificate") {
301 const cppbor::Bstr* valueBstr = valueItem->asBstr();
302 if (valueBstr == nullptr) {
303 LOG(ERROR) << "Value for attestationCertificate is not a bstr";
304 return false;
305 }
306 attestationCertificate_ = valueBstr->value();
307 } else if (key == "secureAccessControlProfiles") {
308 const cppbor::Array* array = valueItem->asArray();
309 if (array == nullptr) {
310 LOG(ERROR) << "Value for attestationCertificate is not an array";
311 return false;
312 }
313 for (size_t m = 0; m < array->size(); m++) {
314 const std::unique_ptr<cppbor::Item>& item = (*array)[m];
315 optional<SecureAccessControlProfile> sacp = parseSacp(*item);
316 if (!sacp) {
317 LOG(ERROR) << "Error parsing SecureAccessControlProfile";
318 return false;
319 }
320 secureAccessControlProfiles_.push_back(sacp.value());
321 }
322
323 } else if (key == "entryData") {
324 const cppbor::Map* map = valueItem->asMap();
325 if (map == nullptr) {
326 LOG(ERROR) << "Value for encryptedChunks is not an map";
327 return false;
328 }
329 for (size_t m = 0; m < map->size(); m++) {
Max Bires5bb33f42021-03-11 00:44:06 -0800330 auto& [ecKeyItem, ecValueItem] = (*map)[m];
David Zeuthenab3e5652019-10-28 13:32:48 -0400331 const cppbor::Tstr* ecTstr = ecKeyItem->asTstr();
332 if (ecTstr == nullptr) {
333 LOG(ERROR) << "Key item in encryptedChunks map is not a tstr";
334 return false;
335 }
336 const string& ecId = ecTstr->value();
337
338 const cppbor::Array* ecEntryArrayItem = ecValueItem->asArray();
339 if (ecEntryArrayItem == nullptr || ecEntryArrayItem->size() < 3) {
340 LOG(ERROR) << "Value item in encryptedChunks map is an array with at least two "
341 "elements";
342 return false;
343 }
344 const cppbor::Int* ecEntrySizeItem = (*ecEntryArrayItem)[0]->asInt();
345 if (ecEntrySizeItem == nullptr) {
346 LOG(ERROR) << "Entry size not a number";
347 return false;
348 }
349 uint64_t entrySize = ecEntrySizeItem->value();
350
David Zeuthena6f9fba2020-02-11 22:08:27 -0500351 optional<vector<int32_t>> accessControlProfileIds =
David Zeuthenab3e5652019-10-28 13:32:48 -0400352 parseAccessControlProfileIds(*(*ecEntryArrayItem)[1]);
353 if (!accessControlProfileIds) {
354 LOG(ERROR) << "Error parsing access control profile ids";
355 return false;
356 }
357
358 optional<vector<vector<uint8_t>>> encryptedChunks =
359 parseEncryptedChunks(*(*ecEntryArrayItem)[2]);
360 if (!encryptedChunks) {
361 LOG(ERROR) << "Error parsing encrypted chunks";
362 return false;
363 }
364
365 EntryData data;
366 data.size = entrySize;
367 data.accessControlProfileIds = accessControlProfileIds.value();
368 data.encryptedChunks = encryptedChunks.value();
369 idToEncryptedChunks_[ecId] = data;
370 }
371
372 } else if (key == "authKeyData") {
373 const cppbor::Array* array = valueItem->asArray();
374 if (array == nullptr) {
375 LOG(ERROR) << "Value for authData is not an array";
376 return false;
377 }
378 for (size_t m = 0; m < array->size(); m++) {
379 const std::unique_ptr<cppbor::Item>& item = (*array)[m];
380 optional<AuthKeyData> authKeyData = parseAuthKeyData(*item);
381 if (!authKeyData) {
382 LOG(ERROR) << "Error parsing AuthKeyData";
383 return false;
384 }
385 authKeyDatas_.push_back(authKeyData.value());
386 }
387
388 } else if (key == "authKeyCount") {
389 const cppbor::Int* number = valueItem->asInt();
390 if (number == nullptr) {
391 LOG(ERROR) << "Value for authKeyCount is not a number";
392 return false;
393 }
394 keyCount_ = number->value();
395
396 } else if (key == "maxUsesPerAuthKey") {
397 const cppbor::Int* number = valueItem->asInt();
398 if (number == nullptr) {
399 LOG(ERROR) << "Value for maxUsesPerAuthKey is not a number";
400 return false;
401 }
402 maxUsesPerKey_ = number->value();
David Zeuthenc239db42022-11-14 15:22:24 -0500403
404 } else if (key == "minValidTimeMillis") {
405 const cppbor::Int* number = valueItem->asInt();
406 if (number == nullptr) {
407 LOG(ERROR) << "Value for minValidTimeMillis is not a number";
408 return false;
409 }
410 minValidTimeMillis_ = number->value();
David Zeuthenab3e5652019-10-28 13:32:48 -0400411 }
412 }
413
David Zeuthena6f9fba2020-02-11 22:08:27 -0500414 if (credentialData_.size() == 0) {
415 LOG(ERROR) << "Missing credentialData";
416 return false;
417 }
418
419 if (attestationCertificate_.size() == 0) {
420 LOG(ERROR) << "Missing attestationCertificate";
David Zeuthenab3e5652019-10-28 13:32:48 -0400421 return false;
422 }
423
424 if (size_t(keyCount_) != authKeyDatas_.size()) {
425 LOG(ERROR) << "keyCount_=" << keyCount_
426 << " != authKeyDatas_.size()=" << authKeyDatas_.size();
427 return false;
428 }
429
430 return true;
431}
432
433const vector<uint8_t>& CredentialData::getCredentialData() const {
434 return credentialData_;
435}
436
437int64_t CredentialData::getSecureUserId() {
438 return secureUserId_;
439}
440
441const vector<uint8_t>& CredentialData::getAttestationCertificate() const {
442 return attestationCertificate_;
443}
444
445const vector<SecureAccessControlProfile>& CredentialData::getSecureAccessControlProfiles() const {
446 return secureAccessControlProfiles_;
447}
448
449bool CredentialData::hasEntryData(const string& namespaceName, const string& entryName) const {
450 string id = namespaceName + ":" + entryName;
451 auto iter = idToEncryptedChunks_.find(id);
452 if (iter == idToEncryptedChunks_.end()) {
453 return false;
454 }
455 return true;
456}
457
458optional<EntryData> CredentialData::getEntryData(const string& namespaceName,
459 const string& entryName) const {
460 string id = namespaceName + ":" + entryName;
461 auto iter = idToEncryptedChunks_.find(id);
462 if (iter == idToEncryptedChunks_.end()) {
463 return {};
464 }
465 return iter->second;
466}
467
468bool CredentialData::deleteCredential() {
469 if (unlink(fileName_.c_str()) != 0) {
470 PLOG(ERROR) << "Error deleting " << fileName_;
471 return false;
472 }
473 return true;
474}
475
476optional<bool> CredentialData::credentialExists(const string& dataPath, uid_t ownerUid,
477 const string& name) {
478 struct stat statbuf;
479 string filename = calculateCredentialFileName(dataPath, ownerUid, name);
480 if (stat(filename.c_str(), &statbuf) != 0) {
481 if (errno == ENOENT) {
482 return false;
483 }
484 PLOG(ERROR) << "Error getting information about " << filename;
485 return {};
486 }
487 return true;
488}
489
490// ---
491
David Zeuthenc239db42022-11-14 15:22:24 -0500492void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
493 int64_t minValidTimeMillis) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400494 keyCount_ = keyCount;
495 maxUsesPerKey_ = maxUsesPerKey;
David Zeuthenc239db42022-11-14 15:22:24 -0500496 minValidTimeMillis_ = minValidTimeMillis;
David Zeuthenab3e5652019-10-28 13:32:48 -0400497
498 // If growing the number of auth keys (prevKeyCount < keyCount_ case) we'll add
499 // new AuthKeyData structs to |authKeyDatas_| and each struct will have empty |certificate|
500 // and |pendingCertificate| fields. Those will be filled out when the
501 // getAuthKeysNeedingCertification() is called.
502 //
503 // If shrinking, we'll just delete the AuthKeyData structs at the end. There's nothing
504 // else to do, the HAL doesn't need to know we're nuking these authentication keys.
505 //
506 // Therefore, in either case it's as simple as just resizing the vector.
507 authKeyDatas_.resize(keyCount_);
508}
509
510const vector<AuthKeyData>& CredentialData::getAuthKeyDatas() const {
511 return authKeyDatas_;
512}
513
David Zeuthenc239db42022-11-14 15:22:24 -0500514tuple<int /* keyCount */, int /*maxUsersPerKey */, int64_t /* minValidTimeMillis */>
515CredentialData::getAvailableAuthenticationKeys() const {
516 return std::make_tuple(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
David Zeuthen472e6c82020-10-16 11:50:13 -0400517}
518
519AuthKeyData* CredentialData::findAuthKey_(bool allowUsingExhaustedKeys,
520 bool allowUsingExpiredKeys) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400521 AuthKeyData* candidate = nullptr;
522
David Zeuthen472e6c82020-10-16 11:50:13 -0400523 int64_t nowMilliSeconds =
524 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
525
David Zeuthenab3e5652019-10-28 13:32:48 -0400526 int n = 0;
David Zeuthenab3e5652019-10-28 13:32:48 -0400527 for (AuthKeyData& data : authKeyDatas_) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400528 if (nowMilliSeconds > data.expirationDateMillisSinceEpoch) {
529 if (!allowUsingExpiredKeys) {
530 continue;
531 }
532 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400533 if (data.certificate.size() != 0) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400534 // Not expired, include in normal check
David Zeuthenab3e5652019-10-28 13:32:48 -0400535 if (candidate == nullptr || data.useCount < candidate->useCount) {
536 candidate = &data;
David Zeuthenab3e5652019-10-28 13:32:48 -0400537 }
538 }
539 n++;
540 }
541
542 if (candidate == nullptr) {
543 return nullptr;
544 }
545
546 if (candidate->useCount >= maxUsesPerKey_ && !allowUsingExhaustedKeys) {
547 return nullptr;
548 }
549
David Zeuthen472e6c82020-10-16 11:50:13 -0400550 return candidate;
551}
552
553const AuthKeyData* CredentialData::selectAuthKey(bool allowUsingExhaustedKeys,
David Zeuthen045a2c82021-09-11 13:52:17 -0400554 bool allowUsingExpiredKeys,
555 bool incrementUsageCount) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400556 AuthKeyData* candidate;
557
558 // First try to find a un-expired key..
559 candidate = findAuthKey_(allowUsingExhaustedKeys, false);
560 if (candidate == nullptr) {
561 // That didn't work, there are no un-expired keys and we don't allow using expired keys.
562 if (!allowUsingExpiredKeys) {
563 return nullptr;
564 }
565
566 // See if there's an expired key then...
567 candidate = findAuthKey_(allowUsingExhaustedKeys, true);
568 if (candidate == nullptr) {
569 return nullptr;
570 }
571 }
572
David Zeuthen045a2c82021-09-11 13:52:17 -0400573 if (incrementUsageCount) {
574 candidate->useCount += 1;
575 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400576 return candidate;
577}
578
David Zeuthena6f9fba2020-02-11 22:08:27 -0500579optional<vector<vector<uint8_t>>>
580CredentialData::getAuthKeysNeedingCertification(const sp<IIdentityCredential>& halBinder) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400581
582 vector<vector<uint8_t>> keysNeedingCert;
583
David Zeuthencbc75ae2023-02-01 10:21:56 -0500584 time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
585 int64_t nowMilliseconds;
586 if (__builtin_mul_overflow(int64_t(now), int64_t(1000), &nowMilliseconds)) {
587 LOG(ERROR) << "Overflow converting " << now << " to milliseconds";
588 return {};
589 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400590
David Zeuthenab3e5652019-10-28 13:32:48 -0400591 for (AuthKeyData& data : authKeyDatas_) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400592 bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
David Zeuthenc239db42022-11-14 15:22:24 -0500593 int64_t expirationDateAdjusted = data.expirationDateMillisSinceEpoch - minValidTimeMillis_;
David Zeuthencbc75ae2023-02-01 10:21:56 -0500594 bool keyBeyondAdjustedExpirationDate = (nowMilliseconds > expirationDateAdjusted);
David Zeuthen472e6c82020-10-16 11:50:13 -0400595 bool newKeyNeeded =
David Zeuthenc239db42022-11-14 15:22:24 -0500596 (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondAdjustedExpirationDate;
David Zeuthenab3e5652019-10-28 13:32:48 -0400597 bool certificationPending = (data.pendingCertificate.size() > 0);
598 if (newKeyNeeded && !certificationPending) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400599 vector<uint8_t> signingKeyBlob;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500600 Certificate signingKeyCertificate;
601 if (!halBinder->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate)
602 .isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400603 LOG(ERROR) << "Error generating signing key-pair";
604 return {};
605 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500606 data.pendingCertificate = signingKeyCertificate.encodedCertificate;
David Zeuthenab3e5652019-10-28 13:32:48 -0400607 data.pendingKeyBlob = signingKeyBlob;
608 certificationPending = true;
609 }
610
611 if (certificationPending) {
612 keysNeedingCert.push_back(data.pendingCertificate);
613 }
614 }
615 return keysNeedingCert;
616}
617
618bool CredentialData::storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
David Zeuthen472e6c82020-10-16 11:50:13 -0400619 int64_t expirationDateMillisSinceEpoch,
David Zeuthenab3e5652019-10-28 13:32:48 -0400620 const vector<uint8_t>& staticAuthData) {
621 for (AuthKeyData& data : authKeyDatas_) {
622 if (data.pendingCertificate == authenticationKey) {
623 data.certificate = data.pendingCertificate;
624 data.keyBlob = data.pendingKeyBlob;
David Zeuthen472e6c82020-10-16 11:50:13 -0400625 data.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
David Zeuthenab3e5652019-10-28 13:32:48 -0400626 data.staticAuthenticationData = staticAuthData;
627 data.pendingCertificate.clear();
628 data.pendingKeyBlob.clear();
629 data.useCount = 0;
630 return true;
631 }
632 }
633 return false;
634}
635
636} // namespace identity
637} // namespace security
638} // namespace android