blob: cb2d6ffd7c20e21752f65dcfadf2c30ec251a4b5 [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 Zeuthene2a78a42020-04-27 13:34:38 -040042 const string& docType, size_t dataChunkSize,
David Zeuthenab3e5652019-10-28 13:32:48 -040043 sp<IWritableIdentityCredential> halBinder)
David Zeuthene2a78a42020-04-27 13:34:38 -040044 : dataPath_(dataPath), credentialName_(credentialName), docType_(docType),
45 dataChunkSize_(dataChunkSize), halBinder_(halBinder) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040046
47WritableCredential::~WritableCredential() {}
48
49Status WritableCredential::ensureAttestationCertificateExists(const vector<uint8_t>& challenge) {
David Zeuthenab3e5652019-10-28 13:32:48 -040050 if (!attestationCertificate_.empty()) {
51 return Status::ok();
52 }
53
David Zeuthenf2a28672020-01-30 16:20:07 -050054 const int32_t callingUid = IPCThreadState::self()->getCallingUid();
55 auto asn1AttestationId = android::security::gather_attestation_application_id(callingUid);
56 if (!asn1AttestationId.isOk()) {
57 LOG(ERROR) << "Failed gathering AttestionApplicationId";
58 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
59 "Failed gathering AttestionApplicationId");
60 }
61
David Zeuthena6f9fba2020-02-11 22:08:27 -050062 vector<Certificate> certificateChain;
63 Status status = halBinder_->getAttestationCertificate(asn1AttestationId.value(), challenge,
64 &certificateChain);
65 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -040066 LOG(ERROR) << "Error calling getAttestationCertificate()";
David Zeuthena6f9fba2020-02-11 22:08:27 -050067 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -040068 }
David Zeuthena6f9fba2020-02-11 22:08:27 -050069
70 vector<vector<uint8_t>> splitCerts;
71 for (const auto& cert : certificateChain) {
72 splitCerts.push_back(cert.encodedCertificate);
73 }
74 attestationCertificate_ =
75 ::android::hardware::identity::support::certificateChainJoin(splitCerts);
76
David Zeuthenab3e5652019-10-28 13:32:48 -040077 return Status::ok();
78}
79
80Status WritableCredential::getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
81 vector<uint8_t>* _aidl_return) {
82
83 Status ensureStatus = ensureAttestationCertificateExists(challenge);
84 if (!ensureStatus.isOk()) {
85 return ensureStatus;
86 }
87
88 *_aidl_return = attestationCertificate_;
89 return Status::ok();
90}
91
David Zeuthene2a78a42020-04-27 13:34:38 -040092ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
93 const vector<AccessControlProfileParcel>& accessControlProfiles,
94 const vector<EntryNamespaceParcel>& entryNamespaces) {
95
96 // Right now, we calculate the size by simply just calculating the
97 // CBOR. There's a little bit of overhead associated with this (as compared
98 // to just adding up sizes) but it's a lot simpler and robust. In the future
99 // if this turns out to be a problem, we can optimize it.
100 //
101
102 cppbor::Array acpArray;
103 for (const AccessControlProfileParcel& profile : accessControlProfiles) {
104 cppbor::Map map;
105 map.add("id", profile.id);
106 if (profile.readerCertificate.size() > 0) {
107 map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate));
108 }
109 if (profile.userAuthenticationRequired) {
110 map.add("userAuthenticationRequired", profile.userAuthenticationRequired);
111 map.add("timeoutMillis", profile.userAuthenticationTimeoutMillis);
112 }
113 acpArray.add(std::move(map));
114 }
115
116 cppbor::Map dataMap;
117 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
118 cppbor::Array entriesArray;
119 for (const EntryParcel& eParcel : ensParcel.entries) {
120 // TODO: ideally do do this without parsing the data (but still validate data is valid
121 // CBOR).
122 auto [itemForValue, _, _2] = cppbor::parse(eParcel.value);
123 if (itemForValue == nullptr) {
124 return -1;
125 }
126 cppbor::Map entryMap;
127 entryMap.add("name", eParcel.name);
128 entryMap.add("value", std::move(itemForValue));
129 cppbor::Array acpIdsArray;
130 for (int32_t id : eParcel.accessControlProfileIds) {
131 acpIdsArray.add(id);
132 }
133 entryMap.add("accessControlProfiles", std::move(acpIdsArray));
134 entriesArray.add(std::move(entryMap));
135 }
136 dataMap.add(ensParcel.namespaceName, std::move(entriesArray));
137 }
138
139 cppbor::Array array;
140 array.add("ProofOfProvisioning");
141 array.add(docType_);
142 array.add(std::move(acpArray));
143 array.add(std::move(dataMap));
144 array.add(false); // testCredential
145 return array.encode().size();
146}
147
David Zeuthenab3e5652019-10-28 13:32:48 -0400148Status
149WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
150 const vector<EntryNamespaceParcel>& entryNamespaces,
151 int64_t secureUserId, vector<uint8_t>* _aidl_return) {
152 Status ensureStatus = ensureAttestationCertificateExists({});
153 if (!ensureStatus.isOk()) {
154 return ensureStatus;
155 }
156
157 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
158 CredentialData data = CredentialData(dataPath_, callingUid, credentialName_);
159
160 // Note: The value 0 is used to convey that no user-authentication is needed for this
161 // credential. This is to allow creating credentials w/o user authentication on devices
162 // where Secure lock screen is not enabled.
163 data.setSecureUserId(secureUserId);
164
165 data.setAttestationCertificate(attestationCertificate_);
166
David Zeuthena6f9fba2020-02-11 22:08:27 -0500167 vector<int32_t> entryCounts;
David Zeuthenab3e5652019-10-28 13:32:48 -0400168 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
169 entryCounts.push_back(ensParcel.entries.size());
170 }
171
David Zeuthene2a78a42020-04-27 13:34:38 -0400172 ssize_t expectedPoPSize =
173 calcExpectedProofOfProvisioningSize(accessControlProfiles, entryNamespaces);
174 if (expectedPoPSize < 0) {
175 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
176 "Data is not valid CBOR");
177 }
178 // This is not catastrophic, we might be dealing with a version 1 implementation which
179 // doesn't have this method.
180 Status status = halBinder_->setExpectedProofOfProvisioningSize(expectedPoPSize);
181 if (!status.isOk()) {
182 LOG(INFO) << "Failed setting expected ProofOfProvisioning size, assuming V1 HAL "
183 << "and continuing";
184 }
185
186 status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500187 if (!status.isOk()) {
188 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400189 }
190
191 for (const AccessControlProfileParcel& acpParcel : accessControlProfiles) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500192 Certificate certificate;
193 certificate.encodedCertificate = acpParcel.readerCertificate;
194 SecureAccessControlProfile profile;
195 status = halBinder_->addAccessControlProfile(
196 acpParcel.id, certificate, acpParcel.userAuthenticationRequired,
197 acpParcel.userAuthenticationTimeoutMillis, secureUserId, &profile);
198 if (!status.isOk()) {
199 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400200 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500201 data.addSecureAccessControlProfile(profile);
David Zeuthenab3e5652019-10-28 13:32:48 -0400202 }
203
204 for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
205 for (const EntryParcel& eParcel : ensParcel.entries) {
206 vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, dataChunkSize_);
207
David Zeuthena6f9fba2020-02-11 22:08:27 -0500208 vector<int32_t> ids;
David Zeuthenab3e5652019-10-28 13:32:48 -0400209 std::copy(eParcel.accessControlProfileIds.begin(),
210 eParcel.accessControlProfileIds.end(), std::back_inserter(ids));
211
David Zeuthena6f9fba2020-02-11 22:08:27 -0500212 status = halBinder_->beginAddEntry(ids, ensParcel.namespaceName, eParcel.name,
213 eParcel.value.size());
214 if (!status.isOk()) {
215 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400216 }
217
218 vector<vector<uint8_t>> encryptedChunks;
219 for (const auto& chunk : chunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500220 vector<uint8_t> encryptedChunk;
221 status = halBinder_->addEntryValue(chunk, &encryptedChunk);
222 if (!status.isOk()) {
223 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400224 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500225 encryptedChunks.push_back(encryptedChunk);
David Zeuthenab3e5652019-10-28 13:32:48 -0400226 }
227 EntryData eData;
228 eData.size = eParcel.value.size();
229 eData.accessControlProfileIds = std::move(ids);
230 eData.encryptedChunks = std::move(encryptedChunks);
231 data.addEntryData(ensParcel.namespaceName, eParcel.name, eData);
232 }
233 }
234
235 vector<uint8_t> credentialData;
236 vector<uint8_t> proofOfProvisioningSignature;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500237 status = halBinder_->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
238 if (!status.isOk()) {
239 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400240 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500241 data.setCredentialData(credentialData);
David Zeuthenab3e5652019-10-28 13:32:48 -0400242
243 if (!data.saveToDisk()) {
244 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
245 "Error saving credential data to disk");
246 }
247
248 *_aidl_return = proofOfProvisioningSignature;
249 return Status::ok();
250}
251
252} // namespace identity
253} // namespace security
254} // namespace android