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