blob: 05c31d3d2b94b4ba945bd43b20b75fed553e3234 [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 "Credential"
18
19#include <android-base/logging.h>
20
21#include <android/hardware/identity/support/IdentityCredentialSupport.h>
22
23#include <android/security/identity/ICredentialStore.h>
24
25#include <android/security/keystore/IKeystoreService.h>
26#include <binder/IPCThreadState.h>
27#include <binder/IServiceManager.h>
28#include <keymasterV4_0/keymaster_utils.h>
29
30#include <cppbor.h>
31#include <cppbor_parse.h>
32
33#include "Credential.h"
34#include "CredentialData.h"
35#include "Util.h"
36
37namespace android {
38namespace security {
39namespace identity {
40
41using std::optional;
42
43using android::security::keystore::IKeystoreService;
44
David Zeuthenab3e5652019-10-28 13:32:48 -040045using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
46using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
47using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
48using ::android::hardware::identity::support::sha256;
49
50using android::hardware::keymaster::V4_0::HardwareAuthToken;
David Zeuthena6f9fba2020-02-11 22:08:27 -050051using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;
David Zeuthenab3e5652019-10-28 13:32:48 -040052
David Zeuthena6f9fba2020-02-11 22:08:27 -050053Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
54 const std::string& credentialName)
55 : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName) {}
David Zeuthenab3e5652019-10-28 13:32:48 -040056
57Credential::~Credential() {}
58
59Status Credential::loadCredential(sp<IIdentityCredentialStore> halStoreBinder) {
60 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
61 sp<CredentialData> data = new CredentialData(dataPath_, callingUid, credentialName_);
62 if (!data->loadFromDisk()) {
63 LOG(ERROR) << "Error loading data for credential";
64 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
65 "Error loading data for credential");
66 }
67
68 data_ = data;
69
David Zeuthenab3e5652019-10-28 13:32:48 -040070 sp<IIdentityCredential> halBinder;
David Zeuthena6f9fba2020-02-11 22:08:27 -050071 Status status =
72 halStoreBinder->getCredential(cipherSuite_, data_->getCredentialData(), &halBinder);
73 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
74 int code = status.serviceSpecificErrorCode();
75 if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
76 return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
77 }
78 }
79 if (!status.isOk()) {
David Zeuthenab3e5652019-10-28 13:32:48 -040080 LOG(ERROR) << "Error getting HAL binder";
81 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
82 }
83
84 halBinder_ = halBinder;
85
86 return Status::ok();
87}
88
89Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
90 *_aidl_return = data_->getAttestationCertificate();
91 return Status::ok();
92}
93
94// Returns operation handle
95Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) {
96
97 selectedAuthKey_ = data_->selectAuthKey(allowUsingExhaustedKeys);
98 if (selectedAuthKey_ == nullptr) {
99 return Status::fromServiceSpecificError(
100 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
101 "No suitable authentication key available");
102 }
103
David Zeuthena6f9fba2020-02-11 22:08:27 -0500104 int64_t challenge;
105 Status status = halBinder_->createAuthChallenge(&challenge);
106 if (!status.isOk()) {
107 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400108 }
109 if (challenge == 0) {
110 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
111 "Returned challenge is 0 (bug in HAL or TA)");
112 }
113
114 selectedChallenge_ = challenge;
115 *_aidl_return = challenge;
116 return Status::ok();
117}
118
119// Returns false if an error occurred communicating with keystore.
120//
121// Sets |authToken| to the empty vector if an auth token couldn't be obtained.
122//
123bool getAuthTokenFromKeystore(uint64_t challenge, uint64_t secureUserId,
124 unsigned int authTokenMaxAgeMillis, vector<uint8_t>& authToken) {
125 sp<IServiceManager> sm = defaultServiceManager();
126 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
127 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
128 if (keystore == nullptr) {
129 return false;
130 }
131
132 vector<uint8_t> returnedAuthToken;
133 Status ret = keystore->getAuthTokenForCredstore(challenge, secureUserId, authTokenMaxAgeMillis,
134 &returnedAuthToken);
135 if (!ret.isOk()) {
136 return false;
137 }
138 authToken = returnedAuthToken;
139 return true;
140}
141
142Status Credential::getEntries(const vector<uint8_t>& requestMessage,
143 const vector<RequestNamespaceParcel>& requestNamespaces,
144 const vector<uint8_t>& sessionTranscript,
145 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
146 GetEntriesResultParcel* _aidl_return) {
147 GetEntriesResultParcel ret;
148
149 // Calculate requestCounts ahead of time and be careful not to include
150 // elements that don't exist.
151 //
152 // Also go through and figure out which access control profiles to include
153 // in the startRetrieval() call.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500154 vector<int32_t> requestCounts;
David Zeuthenab3e5652019-10-28 13:32:48 -0400155 const vector<SecureAccessControlProfile>& allProfiles = data_->getSecureAccessControlProfiles();
156 vector<bool> includeProfile(allProfiles.size());
157 for (const RequestNamespaceParcel& rns : requestNamespaces) {
158 size_t numEntriesInNsToRequest = 0;
159 for (const RequestEntryParcel& rep : rns.entries) {
160 if (data_->hasEntryData(rns.namespaceName, rep.name)) {
161 numEntriesInNsToRequest++;
162 }
163
164 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
165 if (data) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500166 for (int32_t id : data.value().accessControlProfileIds) {
167 if (id >= int32_t(includeProfile.size())) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400168 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
169 << rns.namespaceName << ": " << rep.name;
170 return Status::fromServiceSpecificError(
171 ICredentialStore::ERROR_GENERIC, "Invalid accessProfileId for entry");
172 }
173 includeProfile[id] = true;
174 }
175 }
176 }
177 requestCounts.push_back(numEntriesInNsToRequest);
178 }
179
180 // Now that we know which profiles are needed, send only those to the
181 // HAL.
182 vector<SecureAccessControlProfile> selectedProfiles;
183 for (size_t n = 0; n < allProfiles.size(); n++) {
184 if (includeProfile[n]) {
185 selectedProfiles.push_back(allProfiles[n]);
186 }
187 }
188
189 // Calculate the highest [1] non-zero timeout and if user-auth is needed
190 // ... we need this to select an appropriate authToken.
191 //
192 // [1] : Why do we request the highest timeout and not the lowest? Well, we
193 // return partial results in getEntries e.g. if some data elements
194 // fail to authorize we'll still return the ones that did not fail. So
195 // e.g. consider data elements A and B where A has an ACP with 60
196 // seconds and B has an ACP with 3600 seconds. In this case we'll be
197 // fine with getting an authToken for e.g. 2400 seconds which would
198 // mean returning only B.
199 //
200 bool userAuthNeeded = false;
201 unsigned int authTokenMaxAgeMillis = 0;
202 for (auto& profile : selectedProfiles) {
203 if (profile.userAuthenticationRequired) {
204 userAuthNeeded = true;
205 if (profile.timeoutMillis > 0) {
206 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
207 authTokenMaxAgeMillis = profile.timeoutMillis;
208 }
209 }
210 }
211 }
212
213 // If requesting a challenge-based authToken the idea is that authentication
214 // happens as part of the transaction. As such, authTokenMaxAgeMillis should
215 // be nearly zero. We'll use 10 seconds for this.
216 if (userAuthNeeded && selectedChallenge_ != 0) {
217 authTokenMaxAgeMillis = 10 * 1000;
218 }
219
220 // Only get an authToken if it's actually needed.
David Zeuthena6f9fba2020-02-11 22:08:27 -0500221 AidlHardwareAuthToken aidlAuthToken;
David Zeuthenab3e5652019-10-28 13:32:48 -0400222 if (userAuthNeeded) {
223 vector<uint8_t> authTokenBytes;
224 if (!getAuthTokenFromKeystore(selectedChallenge_, data_->getSecureUserId(),
225 authTokenMaxAgeMillis, authTokenBytes)) {
226 LOG(ERROR) << "Error getting auth token from keystore";
227 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
228 "Error getting auth token from keystore");
229 }
230 if (authTokenBytes.size() > 0) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500231 HardwareAuthToken authToken =
David Zeuthenab3e5652019-10-28 13:32:48 -0400232 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(authTokenBytes);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500233 // Convert from HIDL to AIDL...
234 aidlAuthToken.challenge = int64_t(authToken.challenge);
235 aidlAuthToken.userId = int64_t(authToken.userId);
236 aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
237 aidlAuthToken.authenticatorType =
238 ::android::hardware::keymaster::HardwareAuthenticatorType(
239 int32_t(authToken.authenticatorType));
240 aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
241 aidlAuthToken.mac = authToken.mac;
David Zeuthenab3e5652019-10-28 13:32:48 -0400242 }
243 }
244
David Zeuthen55975ec2020-02-27 14:28:18 -0500245 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
246 // the Java layer. So we could end up with no previously selected auth key and we may
247 // need one.
248 const AuthKeyData* authKey = selectedAuthKey_;
249 if (sessionTranscript.size() > 0) {
250 if (authKey == nullptr) {
251 authKey = data_->selectAuthKey(allowUsingExhaustedKeys);
252 if (authKey == nullptr) {
253 return Status::fromServiceSpecificError(
254 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
255 "No suitable authentication key available");
256 }
257 }
258 }
259 vector<uint8_t> signingKeyBlob;
260 if (authKey != nullptr) {
261 signingKeyBlob = authKey->keyBlob;
262 }
263
264 Status status =
265 halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
266 sessionTranscript, readerSignature, requestCounts);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500267 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
268 int code = status.serviceSpecificErrorCode();
269 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
270 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
271 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
272 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
273 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
274 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
275 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
276 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
277 }
278 }
279 if (!status.isOk()) {
280 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400281 }
282
283 for (const RequestNamespaceParcel& rns : requestNamespaces) {
284 ResultNamespaceParcel resultNamespaceParcel;
285 resultNamespaceParcel.namespaceName = rns.namespaceName;
286
287 for (const RequestEntryParcel& rep : rns.entries) {
288 ResultEntryParcel resultEntryParcel;
289 resultEntryParcel.name = rep.name;
290
291 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
292 if (!data) {
293 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
294 resultNamespaceParcel.entries.push_back(resultEntryParcel);
295 continue;
296 }
297
David Zeuthena6f9fba2020-02-11 22:08:27 -0500298 status =
299 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, data.value().size,
300 data.value().accessControlProfileIds);
301 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
302 int code = status.serviceSpecificErrorCode();
303 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
304 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
305 resultNamespaceParcel.entries.push_back(resultEntryParcel);
306 continue;
307 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
308 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
309 resultNamespaceParcel.entries.push_back(resultEntryParcel);
310 continue;
311 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
312 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
313 resultNamespaceParcel.entries.push_back(resultEntryParcel);
314 continue;
315 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
316 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
317 resultNamespaceParcel.entries.push_back(resultEntryParcel);
318 continue;
319 }
320 }
321 if (!status.isOk()) {
322 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400323 }
324
325 vector<uint8_t> value;
326 for (const auto& encryptedChunk : data.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500327 vector<uint8_t> chunk;
328 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
329 if (!status.isOk()) {
330 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400331 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500332 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400333 }
334
335 resultEntryParcel.status = STATUS_OK;
336 resultEntryParcel.value = value;
337 resultNamespaceParcel.entries.push_back(resultEntryParcel);
338 }
339 ret.resultNamespaces.push_back(resultNamespaceParcel);
340 }
341
David Zeuthen55975ec2020-02-27 14:28:18 -0500342 status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
David Zeuthena6f9fba2020-02-11 22:08:27 -0500343 if (!status.isOk()) {
344 return halStatusToGenericError(status);
345 }
346 if (authKey != nullptr) {
347 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400348 }
349
350 // Ensure useCount is updated on disk.
351 if (authKey != nullptr) {
352 if (!data_->saveToDisk()) {
353 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
354 "Error saving data");
355 }
356 }
357
358 *_aidl_return = ret;
359 return Status::ok();
360}
361
362Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500363 vector<uint8_t> proofOfDeletionSignature;
364 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
365 if (!status.isOk()) {
366 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400367 }
368 if (!data_->deleteCredential()) {
369 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
370 "Error deleting credential data on disk");
371 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500372 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400373 return Status::ok();
374}
375
376Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400377 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500378 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
379 if (!status.isOk()) {
380 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400381 }
382
383 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
384 "ephemeralKey", // Alias for key
385 "0", // Serial, as a decimal number
386 "Credstore", // Issuer
387 "Ephemeral Key", // Subject
388 0, // Validity Not Before
389 24 * 60 * 60); // Validity Not After
390 if (!pkcs12Bytes) {
391 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
392 "Error creating PKCS#12 structure for key pair");
393 }
394 *_aidl_return = pkcs12Bytes.value();
395 return Status::ok();
396}
397
398Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500399 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
400 if (!status.isOk()) {
401 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400402 }
403 return Status::ok();
404}
405
406Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
407 data_->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
408 if (!data_->saveToDisk()) {
409 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
410 "Error saving data");
411 }
412 return Status::ok();
413}
414
415Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
416 optional<vector<vector<uint8_t>>> keysNeedingCert =
417 data_->getAuthKeysNeedingCertification(halBinder_);
418 if (!keysNeedingCert) {
419 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
420 "Error getting auth keys neededing certification");
421 }
422 vector<AuthKeyParcel> authKeyParcels;
423 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
424 AuthKeyParcel authKeyParcel;
425 authKeyParcel.x509cert = key;
426 authKeyParcels.push_back(authKeyParcel);
427 }
428 if (!data_->saveToDisk()) {
429 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
430 "Error saving data");
431 }
432 *_aidl_return = authKeyParcels;
433 return Status::ok();
434}
435
436Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
437 const vector<uint8_t>& staticAuthData) {
438 if (!data_->storeStaticAuthenticationData(authenticationKey.x509cert, staticAuthData)) {
439 return Status::fromServiceSpecificError(
440 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
441 "Error finding authentication key to store static "
442 "authentication data for");
443 }
444 if (!data_->saveToDisk()) {
445 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
446 "Error saving data");
447 }
448 return Status::ok();
449}
450
451Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
452 const vector<AuthKeyData>& authKeyDatas = data_->getAuthKeyDatas();
453 vector<int32_t> ret;
454 for (const AuthKeyData& authKeyData : authKeyDatas) {
455 ret.push_back(authKeyData.useCount);
456 }
457 *_aidl_return = ret;
458 return Status::ok();
459}
460
461} // namespace identity
462} // namespace security
463} // namespace android