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