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