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