blob: d0688b8dd7a6fc61104e3bf6014eb316e6325553 [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
17#define LOG_TAG "WritableCredential"
18
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,
44 sp<IWritableIdentityCredential> halBinder, int halApiVersion)
45 : dataPath_(dataPath), credentialName_(credentialName), docType_(docType), isUpdate_(isUpdate),
46 hwInfo_(std::move(hwInfo)), halBinder_(halBinder), halApiVersion_(halApiVersion) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040047
48WritableCredential::~WritableCredential() {}
49
David Zeuthen472e6c82020-10-16 11:50:13 -040050void WritableCredential::setCredentialUpdatedCallback(
51 std::function<void()>&& onCredentialUpdatedCallback) {
52 onCredentialUpdatedCallback_ = onCredentialUpdatedCallback;
53}
54
David Zeuthenab3e5652019-10-28 13:32:48 -040055Status WritableCredential::ensureAttestationCertificateExists(const vector<uint8_t>& challenge) {
David Zeuthenab3e5652019-10-28 13:32:48 -040056 if (!attestationCertificate_.empty()) {
57 return Status::ok();
58 }
59
David Zeuthenf2a28672020-01-30 16:20:07 -050060 const int32_t callingUid = IPCThreadState::self()->getCallingUid();
61 auto asn1AttestationId = android::security::gather_attestation_application_id(callingUid);
62 if (!asn1AttestationId.isOk()) {
63 LOG(ERROR) << "Failed gathering AttestionApplicationId";
64 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
65 "Failed gathering AttestionApplicationId");
66 }
67
David Zeuthena6f9fba2020-02-11 22:08:27 -050068 vector<Certificate> certificateChain;
69 Status status = halBinder_->getAttestationCertificate(asn1AttestationId.value(), challenge,
70 &certificateChain);
71 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -040072 LOG(ERROR) << "Error calling getAttestationCertificate()";
David Zeuthena6f9fba2020-02-11 22:08:27 -050073 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -040074 }
David Zeuthena6f9fba2020-02-11 22:08:27 -050075
76 vector<vector<uint8_t>> splitCerts;
77 for (const auto& cert : certificateChain) {
78 splitCerts.push_back(cert.encodedCertificate);
79 }
80 attestationCertificate_ =
81 ::android::hardware::identity::support::certificateChainJoin(splitCerts);
82
David Zeuthenab3e5652019-10-28 13:32:48 -040083 return Status::ok();
84}
85
86Status WritableCredential::getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
87 vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -040088 if (isUpdate_) {
89 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
90 "Cannot be called for an update");
91 }
David Zeuthenab3e5652019-10-28 13:32:48 -040092 Status ensureStatus = ensureAttestationCertificateExists(challenge);
93 if (!ensureStatus.isOk()) {
94 return ensureStatus;
95 }
96
97 *_aidl_return = attestationCertificate_;
98 return Status::ok();
99}
100
David Zeuthen472e6c82020-10-16 11:50:13 -0400101void WritableCredential::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
102 attestationCertificate_ = attestationCertificate;
103}
104
105void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
106 keyCount_ = keyCount;
107 maxUsesPerKey_ = maxUsesPerKey;
108}
109
David Zeuthene2a78a42020-04-27 13:34:38 -0400110ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
111 const vector<AccessControlProfileParcel>& accessControlProfiles,
112 const vector<EntryNamespaceParcel>& entryNamespaces) {
113
114 // Right now, we calculate the size by simply just calculating the
115 // CBOR. There's a little bit of overhead associated with this (as compared
116 // to just adding up sizes) but it's a lot simpler and robust. In the future
117 // if this turns out to be a problem, we can optimize it.
118 //
119
120 cppbor::Array acpArray;
121 for (const AccessControlProfileParcel& profile : accessControlProfiles) {
122 cppbor::Map map;
123 map.add("id", profile.id);
124 if (profile.readerCertificate.size() > 0) {
125 map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate));
126 }
127 if (profile.userAuthenticationRequired) {
128 map.add("userAuthenticationRequired", profile.userAuthenticationRequired);
129 map.add("timeoutMillis", profile.userAuthenticationTimeoutMillis);
130 }
131 acpArray.add(std::move(map));
132 }
133
134 cppbor::Map dataMap;
135 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
136 cppbor::Array entriesArray;
137 for (const EntryParcel& eParcel : ensParcel.entries) {
138 // TODO: ideally do do this without parsing the data (but still validate data is valid
139 // CBOR).
140 auto [itemForValue, _, _2] = cppbor::parse(eParcel.value);
141 if (itemForValue == nullptr) {
142 return -1;
143 }
144 cppbor::Map entryMap;
145 entryMap.add("name", eParcel.name);
146 entryMap.add("value", std::move(itemForValue));
147 cppbor::Array acpIdsArray;
148 for (int32_t id : eParcel.accessControlProfileIds) {
149 acpIdsArray.add(id);
150 }
151 entryMap.add("accessControlProfiles", std::move(acpIdsArray));
152 entriesArray.add(std::move(entryMap));
153 }
154 dataMap.add(ensParcel.namespaceName, std::move(entriesArray));
155 }
156
157 cppbor::Array array;
158 array.add("ProofOfProvisioning");
159 array.add(docType_);
160 array.add(std::move(acpArray));
161 array.add(std::move(dataMap));
162 array.add(false); // testCredential
163 return array.encode().size();
164}
165
David Zeuthenab3e5652019-10-28 13:32:48 -0400166Status
167WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
168 const vector<EntryNamespaceParcel>& entryNamespaces,
169 int64_t secureUserId, vector<uint8_t>* _aidl_return) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400170 if (!isUpdate_) {
171 Status ensureStatus =
172 ensureAttestationCertificateExists({0x00}); // Challenge cannot be empty.
173 if (!ensureStatus.isOk()) {
174 return ensureStatus;
175 }
David Zeuthenab3e5652019-10-28 13:32:48 -0400176 }
177
178 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
179 CredentialData data = CredentialData(dataPath_, callingUid, credentialName_);
180
181 // Note: The value 0 is used to convey that no user-authentication is needed for this
182 // credential. This is to allow creating credentials w/o user authentication on devices
183 // where Secure lock screen is not enabled.
184 data.setSecureUserId(secureUserId);
185
186 data.setAttestationCertificate(attestationCertificate_);
187
David Zeuthena6f9fba2020-02-11 22:08:27 -0500188 vector<int32_t> entryCounts;
David Zeuthenab3e5652019-10-28 13:32:48 -0400189 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
190 entryCounts.push_back(ensParcel.entries.size());
191 }
192
David Zeuthene2a78a42020-04-27 13:34:38 -0400193 ssize_t expectedPoPSize =
194 calcExpectedProofOfProvisioningSize(accessControlProfiles, entryNamespaces);
195 if (expectedPoPSize < 0) {
196 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
197 "Data is not valid CBOR");
198 }
199 // This is not catastrophic, we might be dealing with a version 1 implementation which
200 // doesn't have this method.
201 Status status = halBinder_->setExpectedProofOfProvisioningSize(expectedPoPSize);
202 if (!status.isOk()) {
203 LOG(INFO) << "Failed setting expected ProofOfProvisioning size, assuming V1 HAL "
204 << "and continuing";
205 }
206
207 status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500208 if (!status.isOk()) {
209 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400210 }
211
212 for (const AccessControlProfileParcel& acpParcel : accessControlProfiles) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500213 Certificate certificate;
214 certificate.encodedCertificate = acpParcel.readerCertificate;
215 SecureAccessControlProfile profile;
216 status = halBinder_->addAccessControlProfile(
217 acpParcel.id, certificate, acpParcel.userAuthenticationRequired,
218 acpParcel.userAuthenticationTimeoutMillis, secureUserId, &profile);
219 if (!status.isOk()) {
220 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400221 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500222 data.addSecureAccessControlProfile(profile);
David Zeuthenab3e5652019-10-28 13:32:48 -0400223 }
224
225 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
226 for (const EntryParcel& eParcel : ensParcel.entries) {
David Zeuthen472e6c82020-10-16 11:50:13 -0400227 vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, hwInfo_.dataChunkSize);
David Zeuthenab3e5652019-10-28 13:32:48 -0400228
David Zeuthena6f9fba2020-02-11 22:08:27 -0500229 vector<int32_t> ids;
David Zeuthenab3e5652019-10-28 13:32:48 -0400230 std::copy(eParcel.accessControlProfileIds.begin(),
231 eParcel.accessControlProfileIds.end(), std::back_inserter(ids));
232
David Zeuthena6f9fba2020-02-11 22:08:27 -0500233 status = halBinder_->beginAddEntry(ids, ensParcel.namespaceName, eParcel.name,
234 eParcel.value.size());
235 if (!status.isOk()) {
236 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400237 }
238
239 vector<vector<uint8_t>> encryptedChunks;
240 for (const auto& chunk : chunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500241 vector<uint8_t> encryptedChunk;
242 status = halBinder_->addEntryValue(chunk, &encryptedChunk);
243 if (!status.isOk()) {
244 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400245 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500246 encryptedChunks.push_back(encryptedChunk);
David Zeuthenab3e5652019-10-28 13:32:48 -0400247 }
248 EntryData eData;
249 eData.size = eParcel.value.size();
250 eData.accessControlProfileIds = std::move(ids);
251 eData.encryptedChunks = std::move(encryptedChunks);
252 data.addEntryData(ensParcel.namespaceName, eParcel.name, eData);
253 }
254 }
255
256 vector<uint8_t> credentialData;
257 vector<uint8_t> proofOfProvisioningSignature;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500258 status = halBinder_->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
259 if (!status.isOk()) {
260 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400261 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500262 data.setCredentialData(credentialData);
David Zeuthenab3e5652019-10-28 13:32:48 -0400263
David Zeuthen472e6c82020-10-16 11:50:13 -0400264 data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_);
265
David Zeuthenab3e5652019-10-28 13:32:48 -0400266 if (!data.saveToDisk()) {
267 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
268 "Error saving credential data to disk");
269 }
270
David Zeuthen472e6c82020-10-16 11:50:13 -0400271 onCredentialUpdatedCallback_();
272
David Zeuthenab3e5652019-10-28 13:32:48 -0400273 *_aidl_return = proofOfProvisioningSignature;
274 return Status::ok();
275}
276
277} // namespace identity
278} // namespace security
279} // namespace android