blob: d863494e5d37fd1958cc40589534ffbca24c8a9b [file] [log] [blame]
David Zeuthenab3e5652019-10-28 13:32:48 -04001/*
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
David Zeuthen62d43bf2021-03-31 10:41:27 -040017#define LOG_TAG "credstore"
David Zeuthenab3e5652019-10-28 13:32:48 -040018
19#include <android-base/logging.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040020#include <android/hardware/identity/support/IdentityCredentialSupport.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040021#include <android/security/identity/ICredentialStore.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040022#include <binder/IPCThreadState.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040023#include <cppbor.h>
24#include <cppbor_parse.h>
David Zeuthenf2a28672020-01-30 16:20:07 -050025#include <keystore/keystore_attestation_id.h>
David Zeuthenab3e5652019-10-28 13:32:48 -040026
27#include "CredentialData.h"
28#include "Util.h"
29#include "WritableCredential.h"
30
31namespace android {
32namespace security {
33namespace identity {
34
35using ::std::pair;
36
David Zeuthena6f9fba2020-02-11 22:08:27 -050037using ::android::hardware::identity::SecureAccessControlProfile;
David Zeuthenab3e5652019-10-28 13:32:48 -040038
39using ::android::hardware::identity::support::chunkVector;
40
41WritableCredential::WritableCredential(const string& dataPath, const string& credentialName,
David Zeuthen472e6c82020-10-16 11:50:13 -040042 const string& docType, bool isUpdate,
43 HardwareInformation hwInfo,
David Zeuthen27407a52021-03-04 16:32:43 -050044 sp<IWritableIdentityCredential> halBinder)
David Zeuthen472e6c82020-10-16 11:50:13 -040045 : dataPath_(dataPath), credentialName_(credentialName), docType_(docType), isUpdate_(isUpdate),
David Zeuthen27407a52021-03-04 16:32:43 -050046 hwInfo_(std::move(hwInfo)), halBinder_(halBinder) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040047
48WritableCredential::~WritableCredential() {}
49
David Zeuthen27407a52021-03-04 16:32:43 -050050void WritableCredential::setCredentialToReloadWhenUpdated(sp<Credential> credential) {
51 credentialToReloadWhenUpdated_ = credential;
David Zeuthen472e6c82020-10-16 11:50:13 -040052}
53
David Zeuthenab3e5652019-10-28 13:32:48 -040054Status WritableCredential::ensureAttestationCertificateExists(const vector<uint8_t>& challenge) {
David Zeuthenab3e5652019-10-28 13:32:48 -040055 if (!attestationCertificate_.empty()) {
56 return Status::ok();
57 }
58
David Zeuthenf2a28672020-01-30 16:20:07 -050059 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
David Zeuthena6f9fba2020-02-11 22:08:27 -050067 vector<Certificate> certificateChain;
68 Status status = halBinder_->getAttestationCertificate(asn1AttestationId.value(), challenge,
69 &certificateChain);
70 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -040071 LOG(ERROR) << "Error calling getAttestationCertificate()";
David Zeuthena6f9fba2020-02-11 22:08:27 -050072 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -040073 }
David Zeuthena6f9fba2020-02-11 22:08:27 -050074
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
David Zeuthenab3e5652019-10-28 13:32:48 -040082 return Status::ok();
83}
84
85Status WritableCredential::getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
86 vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -040087 if (isUpdate_) {
88 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
89 "Cannot be called for an update");
90 }
David Zeuthenab3e5652019-10-28 13:32:48 -040091 Status ensureStatus = ensureAttestationCertificateExists(challenge);
92 if (!ensureStatus.isOk()) {
93 return ensureStatus;
94 }
95
96 *_aidl_return = attestationCertificate_;
97 return Status::ok();
98}
99
David Zeuthen472e6c82020-10-16 11:50:13 -0400100void WritableCredential::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
101 attestationCertificate_ = attestationCertificate;
102}
103
David Zeuthenc239db42022-11-14 15:22:24 -0500104void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
105 int64_t minValidTimeMillis) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400106 keyCount_ = keyCount;
107 maxUsesPerKey_ = maxUsesPerKey;
David Zeuthenc239db42022-11-14 15:22:24 -0500108 minValidTimeMillis_ = minValidTimeMillis;
David Zeuthen472e6c82020-10-16 11:50:13 -0400109}
110
David Zeuthene2a78a42020-04-27 13:34:38 -0400111ssize_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
David Zeuthenab3e5652019-10-28 13:32:48 -0400167Status
168WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
169 const vector<EntryNamespaceParcel>& entryNamespaces,
170 int64_t secureUserId, vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400171 if (!isUpdate_) {
172 Status ensureStatus =
173 ensureAttestationCertificateExists({0x00}); // Challenge cannot be empty.
174 if (!ensureStatus.isOk()) {
175 return ensureStatus;
176 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400177 }
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
David Zeuthena6f9fba2020-02-11 22:08:27 -0500189 vector<int32_t> entryCounts;
David Zeuthenab3e5652019-10-28 13:32:48 -0400190 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
191 entryCounts.push_back(ensParcel.entries.size());
192 }
193
David Zeuthene2a78a42020-04-27 13:34:38 -0400194 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);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500209 if (!status.isOk()) {
210 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400211 }
212
213 for (const AccessControlProfileParcel& acpParcel : accessControlProfiles) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500214 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);
David Zeuthenab3e5652019-10-28 13:32:48 -0400222 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500223 data.addSecureAccessControlProfile(profile);
David Zeuthenab3e5652019-10-28 13:32:48 -0400224 }
225
226 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
227 for (const EntryParcel& eParcel : ensParcel.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400228 vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, hwInfo_.dataChunkSize);
David Zeuthenab3e5652019-10-28 13:32:48 -0400229
David Zeuthena6f9fba2020-02-11 22:08:27 -0500230 vector<int32_t> ids;
David Zeuthenab3e5652019-10-28 13:32:48 -0400231 std::copy(eParcel.accessControlProfileIds.begin(),
232 eParcel.accessControlProfileIds.end(), std::back_inserter(ids));
233
David Zeuthena6f9fba2020-02-11 22:08:27 -0500234 status = halBinder_->beginAddEntry(ids, ensParcel.namespaceName, eParcel.name,
235 eParcel.value.size());
236 if (!status.isOk()) {
237 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400238 }
239
240 vector<vector<uint8_t>> encryptedChunks;
241 for (const auto& chunk : chunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500242 vector<uint8_t> encryptedChunk;
243 status = halBinder_->addEntryValue(chunk, &encryptedChunk);
244 if (!status.isOk()) {
245 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400246 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500247 encryptedChunks.push_back(encryptedChunk);
David Zeuthenab3e5652019-10-28 13:32:48 -0400248 }
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;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500259 status = halBinder_->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
260 if (!status.isOk()) {
261 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400262 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500263 data.setCredentialData(credentialData);
David Zeuthenab3e5652019-10-28 13:32:48 -0400264
David Zeuthenc239db42022-11-14 15:22:24 -0500265 data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
David Zeuthen472e6c82020-10-16 11:50:13 -0400266
David Zeuthenab3e5652019-10-28 13:32:48 -0400267 if (!data.saveToDisk()) {
268 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
269 "Error saving credential data to disk");
270 }
271
David Zeuthen27407a52021-03-04 16:32:43 -0500272 if (credentialToReloadWhenUpdated_) {
273 credentialToReloadWhenUpdated_->writableCredentialPersonalized();
274 credentialToReloadWhenUpdated_.clear();
275 }
David Zeuthen472e6c82020-10-16 11:50:13 -0400276
David Zeuthenab3e5652019-10-28 13:32:48 -0400277 *_aidl_return = proofOfProvisioningSignature;
278 return Status::ok();
279}
280
281} // namespace identity
282} // namespace security
283} // namespace android