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 "credstore"
18 
19 #include <android-base/logging.h>
20 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
21 #include <android/security/identity/ICredentialStore.h>
22 #include <binder/IPCThreadState.h>
23 #include <cppbor.h>
24 #include <cppbor_parse.h>
25 #include <keystore/keystore_attestation_id.h>
26 
27 #include "CredentialData.h"
28 #include "Util.h"
29 #include "WritableCredential.h"
30 
31 namespace android {
32 namespace security {
33 namespace identity {
34 
35 using ::std::pair;
36 
37 using ::android::hardware::identity::SecureAccessControlProfile;
38 
39 using ::android::hardware::identity::support::chunkVector;
40 
WritableCredential(const string & dataPath,const string & credentialName,const string & docType,bool isUpdate,HardwareInformation hwInfo,sp<IWritableIdentityCredential> halBinder)41 WritableCredential::WritableCredential(const string& dataPath, const string& credentialName,
42                                        const string& docType, bool isUpdate,
43                                        HardwareInformation hwInfo,
44                                        sp<IWritableIdentityCredential> halBinder)
45     : dataPath_(dataPath), credentialName_(credentialName), docType_(docType), isUpdate_(isUpdate),
46       hwInfo_(std::move(hwInfo)), halBinder_(halBinder) {}
47 
~WritableCredential()48 WritableCredential::~WritableCredential() {}
49 
setCredentialToReloadWhenUpdated(sp<Credential> credential)50 void WritableCredential::setCredentialToReloadWhenUpdated(sp<Credential> credential) {
51     credentialToReloadWhenUpdated_ = credential;
52 }
53 
ensureAttestationCertificateExists(const vector<uint8_t> & challenge)54 Status WritableCredential::ensureAttestationCertificateExists(const vector<uint8_t>& challenge) {
55     if (!attestationCertificate_.empty()) {
56         return Status::ok();
57     }
58 
59     const int32_t callingUid = IPCThreadState::self()->getCallingUid();
60     auto asn1AttestationId = android::security::gather_attestation_application_id(callingUid);
61     if (!asn1AttestationId.isOk()) {
62         LOG(ERROR) << "Failed gathering AttestionApplicationId";
63         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
64                                                 "Failed gathering AttestionApplicationId");
65     }
66 
67     vector<Certificate> certificateChain;
68     Status status = halBinder_->getAttestationCertificate(asn1AttestationId.value(), challenge,
69                                                           &certificateChain);
70     if (!status.isOk()) {
71         LOG(ERROR) << "Error calling getAttestationCertificate()";
72         return halStatusToGenericError(status);
73     }
74 
75     vector<vector<uint8_t>> splitCerts;
76     for (const auto& cert : certificateChain) {
77         splitCerts.push_back(cert.encodedCertificate);
78     }
79     attestationCertificate_ =
80         ::android::hardware::identity::support::certificateChainJoin(splitCerts);
81 
82     return Status::ok();
83 }
84 
getCredentialKeyCertificateChain(const vector<uint8_t> & challenge,vector<uint8_t> * _aidl_return)85 Status WritableCredential::getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
86                                                             vector<uint8_t>* _aidl_return) {
87     if (isUpdate_) {
88         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
89                                                 "Cannot be called for an update");
90     }
91     Status ensureStatus = ensureAttestationCertificateExists(challenge);
92     if (!ensureStatus.isOk()) {
93         return ensureStatus;
94     }
95 
96     *_aidl_return = attestationCertificate_;
97     return Status::ok();
98 }
99 
setAttestationCertificate(const vector<uint8_t> & attestationCertificate)100 void WritableCredential::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
101     attestationCertificate_ = attestationCertificate;
102 }
103 
setAvailableAuthenticationKeys(int keyCount,int maxUsesPerKey,int64_t minValidTimeMillis)104 void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
105                                                         int64_t minValidTimeMillis) {
106     keyCount_ = keyCount;
107     maxUsesPerKey_ = maxUsesPerKey;
108     minValidTimeMillis_ = minValidTimeMillis;
109 }
110 
calcExpectedProofOfProvisioningSize(const vector<AccessControlProfileParcel> & accessControlProfiles,const vector<EntryNamespaceParcel> & entryNamespaces)111 ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
112     const vector<AccessControlProfileParcel>& accessControlProfiles,
113     const vector<EntryNamespaceParcel>& entryNamespaces) {
114 
115     // Right now, we calculate the size by simply just calculating the
116     // CBOR. There's a little bit of overhead associated with this (as compared
117     // to just adding up sizes) but it's a lot simpler and robust. In the future
118     // if this turns out to be a problem, we can optimize it.
119     //
120 
121     cppbor::Array acpArray;
122     for (const AccessControlProfileParcel& profile : accessControlProfiles) {
123         cppbor::Map map;
124         map.add("id", profile.id);
125         if (profile.readerCertificate.size() > 0) {
126             map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate));
127         }
128         if (profile.userAuthenticationRequired) {
129             map.add("userAuthenticationRequired", profile.userAuthenticationRequired);
130             map.add("timeoutMillis", profile.userAuthenticationTimeoutMillis);
131         }
132         acpArray.add(std::move(map));
133     }
134 
135     cppbor::Map dataMap;
136     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
137         cppbor::Array entriesArray;
138         for (const EntryParcel& eParcel : ensParcel.entries) {
139             // TODO: ideally do do this without parsing the data (but still validate data is valid
140             // CBOR).
141             auto [itemForValue, _, _2] = cppbor::parse(eParcel.value);
142             if (itemForValue == nullptr) {
143                 return -1;
144             }
145             cppbor::Map entryMap;
146             entryMap.add("name", eParcel.name);
147             entryMap.add("value", std::move(itemForValue));
148             cppbor::Array acpIdsArray;
149             for (int32_t id : eParcel.accessControlProfileIds) {
150                 acpIdsArray.add(id);
151             }
152             entryMap.add("accessControlProfiles", std::move(acpIdsArray));
153             entriesArray.add(std::move(entryMap));
154         }
155         dataMap.add(ensParcel.namespaceName, std::move(entriesArray));
156     }
157 
158     cppbor::Array array;
159     array.add("ProofOfProvisioning");
160     array.add(docType_);
161     array.add(std::move(acpArray));
162     array.add(std::move(dataMap));
163     array.add(false);  // testCredential
164     return array.encode().size();
165 }
166 
167 Status
personalize(const vector<AccessControlProfileParcel> & accessControlProfiles,const vector<EntryNamespaceParcel> & entryNamespaces,int64_t secureUserId,vector<uint8_t> * _aidl_return)168 WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
169                                 const vector<EntryNamespaceParcel>& entryNamespaces,
170                                 int64_t secureUserId, vector<uint8_t>* _aidl_return) {
171     if (!isUpdate_) {
172         Status ensureStatus =
173             ensureAttestationCertificateExists({0x00});  // Challenge cannot be empty.
174         if (!ensureStatus.isOk()) {
175             return ensureStatus;
176         }
177     }
178 
179     uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
180     CredentialData data = CredentialData(dataPath_, callingUid, credentialName_);
181 
182     // Note: The value 0 is used to convey that no user-authentication is needed for this
183     // credential. This is to allow creating credentials w/o user authentication on devices
184     // where Secure lock screen is not enabled.
185     data.setSecureUserId(secureUserId);
186 
187     data.setAttestationCertificate(attestationCertificate_);
188 
189     vector<int32_t> entryCounts;
190     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
191         entryCounts.push_back(ensParcel.entries.size());
192     }
193 
194     ssize_t expectedPoPSize =
195         calcExpectedProofOfProvisioningSize(accessControlProfiles, entryNamespaces);
196     if (expectedPoPSize < 0) {
197         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
198                                                 "Data is not valid CBOR");
199     }
200     // This is not catastrophic, we might be dealing with a version 1 implementation which
201     // doesn't have this method.
202     Status status = halBinder_->setExpectedProofOfProvisioningSize(expectedPoPSize);
203     if (!status.isOk()) {
204         LOG(INFO) << "Failed setting expected ProofOfProvisioning size, assuming V1 HAL "
205                   << "and continuing";
206     }
207 
208     status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts);
209     if (!status.isOk()) {
210         return halStatusToGenericError(status);
211     }
212 
213     for (const AccessControlProfileParcel& acpParcel : accessControlProfiles) {
214         Certificate certificate;
215         certificate.encodedCertificate = acpParcel.readerCertificate;
216         SecureAccessControlProfile profile;
217         status = halBinder_->addAccessControlProfile(
218             acpParcel.id, certificate, acpParcel.userAuthenticationRequired,
219             acpParcel.userAuthenticationTimeoutMillis, secureUserId, &profile);
220         if (!status.isOk()) {
221             return halStatusToGenericError(status);
222         }
223         data.addSecureAccessControlProfile(profile);
224     }
225 
226     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
227         for (const EntryParcel& eParcel : ensParcel.entries) {
228             vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, hwInfo_.dataChunkSize);
229 
230             vector<int32_t> ids;
231             std::copy(eParcel.accessControlProfileIds.begin(),
232                       eParcel.accessControlProfileIds.end(), std::back_inserter(ids));
233 
234             status = halBinder_->beginAddEntry(ids, ensParcel.namespaceName, eParcel.name,
235                                                eParcel.value.size());
236             if (!status.isOk()) {
237                 return halStatusToGenericError(status);
238             }
239 
240             vector<vector<uint8_t>> encryptedChunks;
241             for (const auto& chunk : chunks) {
242                 vector<uint8_t> encryptedChunk;
243                 status = halBinder_->addEntryValue(chunk, &encryptedChunk);
244                 if (!status.isOk()) {
245                     return halStatusToGenericError(status);
246                 }
247                 encryptedChunks.push_back(encryptedChunk);
248             }
249             EntryData eData;
250             eData.size = eParcel.value.size();
251             eData.accessControlProfileIds = std::move(ids);
252             eData.encryptedChunks = std::move(encryptedChunks);
253             data.addEntryData(ensParcel.namespaceName, eParcel.name, eData);
254         }
255     }
256 
257     vector<uint8_t> credentialData;
258     vector<uint8_t> proofOfProvisioningSignature;
259     status = halBinder_->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
260     if (!status.isOk()) {
261         return halStatusToGenericError(status);
262     }
263     data.setCredentialData(credentialData);
264 
265     data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
266 
267     if (!data.saveToDisk()) {
268         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
269                                                 "Error saving credential data to disk");
270     }
271 
272     if (credentialToReloadWhenUpdated_) {
273         credentialToReloadWhenUpdated_->writableCredentialPersonalized();
274         credentialToReloadWhenUpdated_.clear();
275     }
276 
277     *_aidl_return = proofOfProvisioningSignature;
278     return Status::ok();
279 }
280 
281 }  // namespace identity
282 }  // namespace security
283 }  // namespace android
284