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