blob: 604d26219be84e3da111a4d3581ba56d0a67d2cc [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 Zeuthena6f9fba2020-02-11 22:08:27 -0500245 Status status = halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage,
246 sessionTranscript, readerSignature, requestCounts);
247 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
248 int code = status.serviceSpecificErrorCode();
249 if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
250 return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
251 } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
252 return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
253 } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
254 return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
255 } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
256 return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
257 }
258 }
259 if (!status.isOk()) {
260 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400261 }
262
263 for (const RequestNamespaceParcel& rns : requestNamespaces) {
264 ResultNamespaceParcel resultNamespaceParcel;
265 resultNamespaceParcel.namespaceName = rns.namespaceName;
266
267 for (const RequestEntryParcel& rep : rns.entries) {
268 ResultEntryParcel resultEntryParcel;
269 resultEntryParcel.name = rep.name;
270
271 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
272 if (!data) {
273 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
274 resultNamespaceParcel.entries.push_back(resultEntryParcel);
275 continue;
276 }
277
David Zeuthena6f9fba2020-02-11 22:08:27 -0500278 status =
279 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, data.value().size,
280 data.value().accessControlProfileIds);
281 if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
282 int code = status.serviceSpecificErrorCode();
283 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
284 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
285 resultNamespaceParcel.entries.push_back(resultEntryParcel);
286 continue;
287 } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
288 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
289 resultNamespaceParcel.entries.push_back(resultEntryParcel);
290 continue;
291 } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
292 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
293 resultNamespaceParcel.entries.push_back(resultEntryParcel);
294 continue;
295 } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
296 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
297 resultNamespaceParcel.entries.push_back(resultEntryParcel);
298 continue;
299 }
300 }
301 if (!status.isOk()) {
302 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400303 }
304
305 vector<uint8_t> value;
306 for (const auto& encryptedChunk : data.value().encryptedChunks) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500307 vector<uint8_t> chunk;
308 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
309 if (!status.isOk()) {
310 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400311 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500312 value.insert(value.end(), chunk.begin(), chunk.end());
David Zeuthenab3e5652019-10-28 13:32:48 -0400313 }
314
315 resultEntryParcel.status = STATUS_OK;
316 resultEntryParcel.value = value;
317 resultNamespaceParcel.entries.push_back(resultEntryParcel);
318 }
319 ret.resultNamespaces.push_back(resultNamespaceParcel);
320 }
321
322 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
323 // the Java layer. So we could end up with no previously selected auth key and we may
324 // need one.
325 const AuthKeyData* authKey = selectedAuthKey_;
326 if (sessionTranscript.size() > 0) {
327 if (authKey == nullptr) {
328 authKey = data_->selectAuthKey(allowUsingExhaustedKeys);
329 if (authKey == nullptr) {
330 return Status::fromServiceSpecificError(
331 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
332 "No suitable authentication key available");
333 }
334 }
335 }
336
337 vector<uint8_t> signingKeyBlob;
338 if (authKey != nullptr) {
339 signingKeyBlob = authKey->keyBlob;
340 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500341 status = halBinder_->finishRetrieval(signingKeyBlob, &ret.mac, &ret.deviceNameSpaces);
342 if (!status.isOk()) {
343 return halStatusToGenericError(status);
344 }
345 if (authKey != nullptr) {
346 ret.staticAuthenticationData = authKey->staticAuthenticationData;
David Zeuthenab3e5652019-10-28 13:32:48 -0400347 }
348
349 // Ensure useCount is updated on disk.
350 if (authKey != nullptr) {
351 if (!data_->saveToDisk()) {
352 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
353 "Error saving data");
354 }
355 }
356
357 *_aidl_return = ret;
358 return Status::ok();
359}
360
361Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500362 vector<uint8_t> proofOfDeletionSignature;
363 Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
364 if (!status.isOk()) {
365 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400366 }
367 if (!data_->deleteCredential()) {
368 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
369 "Error deleting credential data on disk");
370 }
David Zeuthena6f9fba2020-02-11 22:08:27 -0500371 *_aidl_return = proofOfDeletionSignature;
David Zeuthenab3e5652019-10-28 13:32:48 -0400372 return Status::ok();
373}
374
375Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
David Zeuthenab3e5652019-10-28 13:32:48 -0400376 vector<uint8_t> keyPair;
David Zeuthena6f9fba2020-02-11 22:08:27 -0500377 Status status = halBinder_->createEphemeralKeyPair(&keyPair);
378 if (!status.isOk()) {
379 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400380 }
381
382 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
383 "ephemeralKey", // Alias for key
384 "0", // Serial, as a decimal number
385 "Credstore", // Issuer
386 "Ephemeral Key", // Subject
387 0, // Validity Not Before
388 24 * 60 * 60); // Validity Not After
389 if (!pkcs12Bytes) {
390 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
391 "Error creating PKCS#12 structure for key pair");
392 }
393 *_aidl_return = pkcs12Bytes.value();
394 return Status::ok();
395}
396
397Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
David Zeuthena6f9fba2020-02-11 22:08:27 -0500398 Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
399 if (!status.isOk()) {
400 return halStatusToGenericError(status);
David Zeuthenab3e5652019-10-28 13:32:48 -0400401 }
402 return Status::ok();
403}
404
405Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
406 data_->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
407 if (!data_->saveToDisk()) {
408 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
409 "Error saving data");
410 }
411 return Status::ok();
412}
413
414Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
415 optional<vector<vector<uint8_t>>> keysNeedingCert =
416 data_->getAuthKeysNeedingCertification(halBinder_);
417 if (!keysNeedingCert) {
418 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
419 "Error getting auth keys neededing certification");
420 }
421 vector<AuthKeyParcel> authKeyParcels;
422 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
423 AuthKeyParcel authKeyParcel;
424 authKeyParcel.x509cert = key;
425 authKeyParcels.push_back(authKeyParcel);
426 }
427 if (!data_->saveToDisk()) {
428 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
429 "Error saving data");
430 }
431 *_aidl_return = authKeyParcels;
432 return Status::ok();
433}
434
435Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
436 const vector<uint8_t>& staticAuthData) {
437 if (!data_->storeStaticAuthenticationData(authenticationKey.x509cert, staticAuthData)) {
438 return Status::fromServiceSpecificError(
439 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
440 "Error finding authentication key to store static "
441 "authentication data for");
442 }
443 if (!data_->saveToDisk()) {
444 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
445 "Error saving data");
446 }
447 return Status::ok();
448}
449
450Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
451 const vector<AuthKeyData>& authKeyDatas = data_->getAuthKeyDatas();
452 vector<int32_t> ret;
453 for (const AuthKeyData& authKeyData : authKeyDatas) {
454 ret.push_back(authKeyData.useCount);
455 }
456 *_aidl_return = ret;
457 return Status::ok();
458}
459
460} // namespace identity
461} // namespace security
462} // namespace android