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)104 void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
105     keyCount_ = keyCount;
106     maxUsesPerKey_ = maxUsesPerKey;
107 }
108 
calcExpectedProofOfProvisioningSize(const vector<AccessControlProfileParcel> & accessControlProfiles,const vector<EntryNamespaceParcel> & entryNamespaces)109 ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
110     const vector<AccessControlProfileParcel>& accessControlProfiles,
111     const vector<EntryNamespaceParcel>& entryNamespaces) {
112 
113     // Right now, we calculate the size by simply just calculating the
114     // CBOR. There's a little bit of overhead associated with this (as compared
115     // to just adding up sizes) but it's a lot simpler and robust. In the future
116     // if this turns out to be a problem, we can optimize it.
117     //
118 
119     cppbor::Array acpArray;
120     for (const AccessControlProfileParcel& profile : accessControlProfiles) {
121         cppbor::Map map;
122         map.add("id", profile.id);
123         if (profile.readerCertificate.size() > 0) {
124             map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate));
125         }
126         if (profile.userAuthenticationRequired) {
127             map.add("userAuthenticationRequired", profile.userAuthenticationRequired);
128             map.add("timeoutMillis", profile.userAuthenticationTimeoutMillis);
129         }
130         acpArray.add(std::move(map));
131     }
132 
133     cppbor::Map dataMap;
134     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
135         cppbor::Array entriesArray;
136         for (const EntryParcel& eParcel : ensParcel.entries) {
137             // TODO: ideally do do this without parsing the data (but still validate data is valid
138             // CBOR).
139             auto [itemForValue, _, _2] = cppbor::parse(eParcel.value);
140             if (itemForValue == nullptr) {
141                 return -1;
142             }
143             cppbor::Map entryMap;
144             entryMap.add("name", eParcel.name);
145             entryMap.add("value", std::move(itemForValue));
146             cppbor::Array acpIdsArray;
147             for (int32_t id : eParcel.accessControlProfileIds) {
148                 acpIdsArray.add(id);
149             }
150             entryMap.add("accessControlProfiles", std::move(acpIdsArray));
151             entriesArray.add(std::move(entryMap));
152         }
153         dataMap.add(ensParcel.namespaceName, std::move(entriesArray));
154     }
155 
156     cppbor::Array array;
157     array.add("ProofOfProvisioning");
158     array.add(docType_);
159     array.add(std::move(acpArray));
160     array.add(std::move(dataMap));
161     array.add(false);  // testCredential
162     return array.encode().size();
163 }
164 
165 Status
personalize(const vector<AccessControlProfileParcel> & accessControlProfiles,const vector<EntryNamespaceParcel> & entryNamespaces,int64_t secureUserId,vector<uint8_t> * _aidl_return)166 WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
167                                 const vector<EntryNamespaceParcel>& entryNamespaces,
168                                 int64_t secureUserId, vector<uint8_t>* _aidl_return) {
169     if (!isUpdate_) {
170         Status ensureStatus =
171             ensureAttestationCertificateExists({0x00});  // Challenge cannot be empty.
172         if (!ensureStatus.isOk()) {
173             return ensureStatus;
174         }
175     }
176 
177     uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
178     CredentialData data = CredentialData(dataPath_, callingUid, credentialName_);
179 
180     // Note: The value 0 is used to convey that no user-authentication is needed for this
181     // credential. This is to allow creating credentials w/o user authentication on devices
182     // where Secure lock screen is not enabled.
183     data.setSecureUserId(secureUserId);
184 
185     data.setAttestationCertificate(attestationCertificate_);
186 
187     vector<int32_t> entryCounts;
188     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
189         entryCounts.push_back(ensParcel.entries.size());
190     }
191 
192     ssize_t expectedPoPSize =
193         calcExpectedProofOfProvisioningSize(accessControlProfiles, entryNamespaces);
194     if (expectedPoPSize < 0) {
195         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
196                                                 "Data is not valid CBOR");
197     }
198     // This is not catastrophic, we might be dealing with a version 1 implementation which
199     // doesn't have this method.
200     Status status = halBinder_->setExpectedProofOfProvisioningSize(expectedPoPSize);
201     if (!status.isOk()) {
202         LOG(INFO) << "Failed setting expected ProofOfProvisioning size, assuming V1 HAL "
203                   << "and continuing";
204     }
205 
206     status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts);
207     if (!status.isOk()) {
208         return halStatusToGenericError(status);
209     }
210 
211     for (const AccessControlProfileParcel& acpParcel : accessControlProfiles) {
212         Certificate certificate;
213         certificate.encodedCertificate = acpParcel.readerCertificate;
214         SecureAccessControlProfile profile;
215         status = halBinder_->addAccessControlProfile(
216             acpParcel.id, certificate, acpParcel.userAuthenticationRequired,
217             acpParcel.userAuthenticationTimeoutMillis, secureUserId, &profile);
218         if (!status.isOk()) {
219             return halStatusToGenericError(status);
220         }
221         data.addSecureAccessControlProfile(profile);
222     }
223 
224     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
225         for (const EntryParcel& eParcel : ensParcel.entries) {
226             vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, hwInfo_.dataChunkSize);
227 
228             vector<int32_t> ids;
229             std::copy(eParcel.accessControlProfileIds.begin(),
230                       eParcel.accessControlProfileIds.end(), std::back_inserter(ids));
231 
232             status = halBinder_->beginAddEntry(ids, ensParcel.namespaceName, eParcel.name,
233                                                eParcel.value.size());
234             if (!status.isOk()) {
235                 return halStatusToGenericError(status);
236             }
237 
238             vector<vector<uint8_t>> encryptedChunks;
239             for (const auto& chunk : chunks) {
240                 vector<uint8_t> encryptedChunk;
241                 status = halBinder_->addEntryValue(chunk, &encryptedChunk);
242                 if (!status.isOk()) {
243                     return halStatusToGenericError(status);
244                 }
245                 encryptedChunks.push_back(encryptedChunk);
246             }
247             EntryData eData;
248             eData.size = eParcel.value.size();
249             eData.accessControlProfileIds = std::move(ids);
250             eData.encryptedChunks = std::move(encryptedChunks);
251             data.addEntryData(ensParcel.namespaceName, eParcel.name, eData);
252         }
253     }
254 
255     vector<uint8_t> credentialData;
256     vector<uint8_t> proofOfProvisioningSignature;
257     status = halBinder_->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
258     if (!status.isOk()) {
259         return halStatusToGenericError(status);
260     }
261     data.setCredentialData(credentialData);
262 
263     data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_);
264 
265     if (!data.saveToDisk()) {
266         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
267                                                 "Error saving credential data to disk");
268     }
269 
270     if (credentialToReloadWhenUpdated_) {
271         credentialToReloadWhenUpdated_->writableCredentialPersonalized();
272         credentialToReloadWhenUpdated_.clear();
273     }
274 
275     *_aidl_return = proofOfProvisioningSignature;
276     return Status::ok();
277 }
278 
279 }  // namespace identity
280 }  // namespace security
281 }  // namespace android
282