blob: 6b0330996e87d03eca1fca29117c5633a2d66222 [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
45using ::android::hardware::hidl_vec;
46
47using ::android::hardware::identity::V1_0::Result;
48using ::android::hardware::identity::V1_0::ResultCode;
49using ::android::hardware::identity::V1_0::SecureAccessControlProfile;
50
51using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
52using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
53using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
54using ::android::hardware::identity::support::sha256;
55
56using android::hardware::keymaster::V4_0::HardwareAuthToken;
57
58Credential::Credential(const std::string& dataPath, const std::string& credentialName)
59 : dataPath_(dataPath), credentialName_(credentialName) {}
60
61Credential::~Credential() {}
62
63Status Credential::loadCredential(sp<IIdentityCredentialStore> halStoreBinder) {
64 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
65 sp<CredentialData> data = new CredentialData(dataPath_, callingUid, credentialName_);
66 if (!data->loadFromDisk()) {
67 LOG(ERROR) << "Error loading data for credential";
68 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
69 "Error loading data for credential");
70 }
71
72 data_ = data;
73
74 Result result;
75 sp<IIdentityCredential> halBinder;
76 halStoreBinder->getCredential(
77 data_->getCredentialData(),
78 [&](const Result& _result, const sp<IIdentityCredential>& _halBinder) {
79 result = _result;
80 halBinder = _halBinder;
81 });
82 if (result.code != ResultCode::OK) {
83 LOG(ERROR) << "Error getting HAL binder";
84 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
85 }
86
87 halBinder_ = halBinder;
88
89 return Status::ok();
90}
91
92Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
93 *_aidl_return = data_->getAttestationCertificate();
94 return Status::ok();
95}
96
97// Returns operation handle
98Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) {
99
100 selectedAuthKey_ = data_->selectAuthKey(allowUsingExhaustedKeys);
101 if (selectedAuthKey_ == nullptr) {
102 return Status::fromServiceSpecificError(
103 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
104 "No suitable authentication key available");
105 }
106
107 Result result;
108 uint64_t challenge;
109 halBinder_->createAuthChallenge([&](const Result& _result, uint64_t _challenge) {
110 result = _result;
111 challenge = _challenge;
112 });
113 if (result.code != ResultCode::OK) {
114 LOG(ERROR) << "createAuthChallenge() failed " << ((int)result.code) << ": "
115 << result.message;
116 return halResultToGenericError(result);
117 }
118 if (challenge == 0) {
119 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
120 "Returned challenge is 0 (bug in HAL or TA)");
121 }
122
123 selectedChallenge_ = challenge;
124 *_aidl_return = challenge;
125 return Status::ok();
126}
127
128// Returns false if an error occurred communicating with keystore.
129//
130// Sets |authToken| to the empty vector if an auth token couldn't be obtained.
131//
132bool getAuthTokenFromKeystore(uint64_t challenge, uint64_t secureUserId,
133 unsigned int authTokenMaxAgeMillis, vector<uint8_t>& authToken) {
134 sp<IServiceManager> sm = defaultServiceManager();
135 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
136 sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
137 if (keystore == nullptr) {
138 return false;
139 }
140
141 vector<uint8_t> returnedAuthToken;
142 Status ret = keystore->getAuthTokenForCredstore(challenge, secureUserId, authTokenMaxAgeMillis,
143 &returnedAuthToken);
144 if (!ret.isOk()) {
145 return false;
146 }
147 authToken = returnedAuthToken;
148 return true;
149}
150
151Status Credential::getEntries(const vector<uint8_t>& requestMessage,
152 const vector<RequestNamespaceParcel>& requestNamespaces,
153 const vector<uint8_t>& sessionTranscript,
154 const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
155 GetEntriesResultParcel* _aidl_return) {
156 GetEntriesResultParcel ret;
157
158 // Calculate requestCounts ahead of time and be careful not to include
159 // elements that don't exist.
160 //
161 // Also go through and figure out which access control profiles to include
162 // in the startRetrieval() call.
163 vector<uint16_t> requestCounts;
164 const vector<SecureAccessControlProfile>& allProfiles = data_->getSecureAccessControlProfiles();
165 vector<bool> includeProfile(allProfiles.size());
166 for (const RequestNamespaceParcel& rns : requestNamespaces) {
167 size_t numEntriesInNsToRequest = 0;
168 for (const RequestEntryParcel& rep : rns.entries) {
169 if (data_->hasEntryData(rns.namespaceName, rep.name)) {
170 numEntriesInNsToRequest++;
171 }
172
173 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
174 if (data) {
175 for (uint16_t id : data.value().accessControlProfileIds) {
176 if (id >= includeProfile.size()) {
177 LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
178 << rns.namespaceName << ": " << rep.name;
179 return Status::fromServiceSpecificError(
180 ICredentialStore::ERROR_GENERIC, "Invalid accessProfileId for entry");
181 }
182 includeProfile[id] = true;
183 }
184 }
185 }
186 requestCounts.push_back(numEntriesInNsToRequest);
187 }
188
189 // Now that we know which profiles are needed, send only those to the
190 // HAL.
191 vector<SecureAccessControlProfile> selectedProfiles;
192 for (size_t n = 0; n < allProfiles.size(); n++) {
193 if (includeProfile[n]) {
194 selectedProfiles.push_back(allProfiles[n]);
195 }
196 }
197
198 // Calculate the highest [1] non-zero timeout and if user-auth is needed
199 // ... we need this to select an appropriate authToken.
200 //
201 // [1] : Why do we request the highest timeout and not the lowest? Well, we
202 // return partial results in getEntries e.g. if some data elements
203 // fail to authorize we'll still return the ones that did not fail. So
204 // e.g. consider data elements A and B where A has an ACP with 60
205 // seconds and B has an ACP with 3600 seconds. In this case we'll be
206 // fine with getting an authToken for e.g. 2400 seconds which would
207 // mean returning only B.
208 //
209 bool userAuthNeeded = false;
210 unsigned int authTokenMaxAgeMillis = 0;
211 for (auto& profile : selectedProfiles) {
212 if (profile.userAuthenticationRequired) {
213 userAuthNeeded = true;
214 if (profile.timeoutMillis > 0) {
215 if (profile.timeoutMillis > authTokenMaxAgeMillis) {
216 authTokenMaxAgeMillis = profile.timeoutMillis;
217 }
218 }
219 }
220 }
221
222 // If requesting a challenge-based authToken the idea is that authentication
223 // happens as part of the transaction. As such, authTokenMaxAgeMillis should
224 // be nearly zero. We'll use 10 seconds for this.
225 if (userAuthNeeded && selectedChallenge_ != 0) {
226 authTokenMaxAgeMillis = 10 * 1000;
227 }
228
229 // Only get an authToken if it's actually needed.
230 HardwareAuthToken authToken;
231 if (userAuthNeeded) {
232 vector<uint8_t> authTokenBytes;
233 if (!getAuthTokenFromKeystore(selectedChallenge_, data_->getSecureUserId(),
234 authTokenMaxAgeMillis, authTokenBytes)) {
235 LOG(ERROR) << "Error getting auth token from keystore";
236 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
237 "Error getting auth token from keystore");
238 }
239 if (authTokenBytes.size() > 0) {
240 authToken =
241 android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(authTokenBytes);
242 }
243 }
244
245 Result result;
246 halBinder_->startRetrieval(selectedProfiles, authToken, requestMessage, sessionTranscript,
247 readerSignature, requestCounts,
248 [&](const Result& _result) { result = _result; });
249 if (result.code == ResultCode::EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
250 LOG(ERROR) << "startRetrieval() failed " << ((int)result.code) << ": " << result.message;
251 return Status::fromServiceSpecificError(
252 ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND, result.message.c_str());
253 } else if (result.code == ResultCode::READER_SIGNATURE_CHECK_FAILED) {
254 LOG(ERROR) << "startRetrieval() failed " << ((int)result.code) << ": " << result.message;
255 return Status::fromServiceSpecificError(ICredentialStore::ERROR_INVALID_READER_SIGNATURE,
256 result.message.c_str());
257 } else if (result.code == ResultCode::INVALID_ITEMS_REQUEST_MESSAGE) {
258 LOG(ERROR) << "startRetrieval() failed " << ((int)result.code) << ": " << result.message;
259 return Status::fromServiceSpecificError(
260 ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE, result.message.c_str());
261 } else if (result.code == ResultCode::SESSION_TRANSCRIPT_MISMATCH) {
262 LOG(ERROR) << "startRetrieval() failed " << ((int)result.code) << ": " << result.message;
263 return Status::fromServiceSpecificError(ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH,
264 result.message.c_str());
265 } else if (result.code != ResultCode::OK) {
266 LOG(ERROR) << "startRetrieval() failed " << ((int)result.code) << ": " << result.message;
267 return halResultToGenericError(result);
268 }
269
270 for (const RequestNamespaceParcel& rns : requestNamespaces) {
271 ResultNamespaceParcel resultNamespaceParcel;
272 resultNamespaceParcel.namespaceName = rns.namespaceName;
273
274 for (const RequestEntryParcel& rep : rns.entries) {
275 ResultEntryParcel resultEntryParcel;
276 resultEntryParcel.name = rep.name;
277
278 optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
279 if (!data) {
280 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
281 resultNamespaceParcel.entries.push_back(resultEntryParcel);
282 continue;
283 }
284
285 halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, data.value().size,
286 data.value().accessControlProfileIds,
287 [&](const Result& _result) { result = _result; });
288 if (result.code == ResultCode::USER_AUTHENTICATION_FAILED) {
289 resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
290 resultNamespaceParcel.entries.push_back(resultEntryParcel);
291 continue;
292 } else if (result.code == ResultCode::READER_AUTHENTICATION_FAILED) {
293 resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
294 resultNamespaceParcel.entries.push_back(resultEntryParcel);
295 continue;
296 } else if (result.code == ResultCode::NOT_IN_REQUEST_MESSAGE) {
297 resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
298 resultNamespaceParcel.entries.push_back(resultEntryParcel);
299 continue;
300 } else if (result.code == ResultCode::NO_ACCESS_CONTROL_PROFILES) {
301 resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
302 resultNamespaceParcel.entries.push_back(resultEntryParcel);
303 continue;
304 } else if (result.code != ResultCode::OK) {
305 LOG(ERROR) << "startRetrieveEntryValue() failed " << ((int)result.code) << ": "
306 << result.message;
307 return halResultToGenericError(result);
308 }
309
310 vector<uint8_t> value;
311 for (const auto& encryptedChunk : data.value().encryptedChunks) {
312 halBinder_->retrieveEntryValue(
313 encryptedChunk, [&](const Result& _result, const hidl_vec<uint8_t>& chunk) {
314 result = _result;
315 value.insert(value.end(), chunk.begin(), chunk.end());
316 });
317 if (result.code != ResultCode::OK) {
318 LOG(ERROR) << "retrieveEntryValue failed() " << ((int)result.code) << ": "
319 << result.message;
320 return halResultToGenericError(result);
321 }
322 }
323
324 resultEntryParcel.status = STATUS_OK;
325 resultEntryParcel.value = value;
326 resultNamespaceParcel.entries.push_back(resultEntryParcel);
327 }
328 ret.resultNamespaces.push_back(resultNamespaceParcel);
329 }
330
331 // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
332 // the Java layer. So we could end up with no previously selected auth key and we may
333 // need one.
334 const AuthKeyData* authKey = selectedAuthKey_;
335 if (sessionTranscript.size() > 0) {
336 if (authKey == nullptr) {
337 authKey = data_->selectAuthKey(allowUsingExhaustedKeys);
338 if (authKey == nullptr) {
339 return Status::fromServiceSpecificError(
340 ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
341 "No suitable authentication key available");
342 }
343 }
344 }
345
346 vector<uint8_t> signingKeyBlob;
347 if (authKey != nullptr) {
348 signingKeyBlob = authKey->keyBlob;
349 }
350 halBinder_->finishRetrieval(signingKeyBlob, [&](const Result& _result,
351 const hidl_vec<uint8_t>& _mac,
352 const hidl_vec<uint8_t>& _deviceNameSpaces) {
353 result = _result;
354 ret.mac = _mac;
355 ret.deviceNameSpaces = _deviceNameSpaces;
356 if (authKey != nullptr) {
357 ret.staticAuthenticationData = authKey->staticAuthenticationData;
358 }
359 });
360 if (result.code != ResultCode::OK) {
361 LOG(ERROR) << "finishRetrieval failed() " << ((int)result.code) << ": " << result.message;
362 return halResultToGenericError(result);
363 }
364
365 // Ensure useCount is updated on disk.
366 if (authKey != nullptr) {
367 if (!data_->saveToDisk()) {
368 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
369 "Error saving data");
370 }
371 }
372
373 *_aidl_return = ret;
374 return Status::ok();
375}
376
377Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
378 Result result;
379 halBinder_->deleteCredential(
380 [&](const Result& _result, const hidl_vec<uint8_t>& _proofOfDeletionSignature) {
381 result = _result;
382 *_aidl_return = _proofOfDeletionSignature;
383 });
384 if (result.code != ResultCode::OK) {
385 LOG(ERROR) << "deleteCredential failed() " << ((int)result.code) << ": " << result.message;
386 return halResultToGenericError(result);
387 }
388 if (!data_->deleteCredential()) {
389 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
390 "Error deleting credential data on disk");
391 }
392 return Status::ok();
393}
394
395Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
396 Result result;
397
398 vector<uint8_t> keyPair;
399 halBinder_->createEphemeralKeyPair(
400 [&](const Result& _result, const hidl_vec<uint8_t>& _keyPair) {
401 result = _result;
402 keyPair = _keyPair;
403 });
404 if (result.code != ResultCode::OK) {
405 LOG(ERROR) << "createEphemeralKeyPair failed() " << ((int)result.code) << ": "
406 << result.message;
407 return halResultToGenericError(result);
408 }
409
410 optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
411 "ephemeralKey", // Alias for key
412 "0", // Serial, as a decimal number
413 "Credstore", // Issuer
414 "Ephemeral Key", // Subject
415 0, // Validity Not Before
416 24 * 60 * 60); // Validity Not After
417 if (!pkcs12Bytes) {
418 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
419 "Error creating PKCS#12 structure for key pair");
420 }
421 *_aidl_return = pkcs12Bytes.value();
422 return Status::ok();
423}
424
425Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
426 Result result;
427 halBinder_->setReaderEphemeralPublicKey(publicKey,
428 [&](const Result& _result) { result = _result; });
429 if (result.code != ResultCode::OK) {
430 LOG(ERROR) << "setReaderEphemeralPublicKey failed() " << ((int)result.code) << ": "
431 << result.message;
432 return halResultToGenericError(result);
433 }
434 return Status::ok();
435}
436
437Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
438 data_->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
439 if (!data_->saveToDisk()) {
440 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
441 "Error saving data");
442 }
443 return Status::ok();
444}
445
446Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
447 optional<vector<vector<uint8_t>>> keysNeedingCert =
448 data_->getAuthKeysNeedingCertification(halBinder_);
449 if (!keysNeedingCert) {
450 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
451 "Error getting auth keys neededing certification");
452 }
453 vector<AuthKeyParcel> authKeyParcels;
454 for (const vector<uint8_t>& key : keysNeedingCert.value()) {
455 AuthKeyParcel authKeyParcel;
456 authKeyParcel.x509cert = key;
457 authKeyParcels.push_back(authKeyParcel);
458 }
459 if (!data_->saveToDisk()) {
460 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
461 "Error saving data");
462 }
463 *_aidl_return = authKeyParcels;
464 return Status::ok();
465}
466
467Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
468 const vector<uint8_t>& staticAuthData) {
469 if (!data_->storeStaticAuthenticationData(authenticationKey.x509cert, staticAuthData)) {
470 return Status::fromServiceSpecificError(
471 ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
472 "Error finding authentication key to store static "
473 "authentication data for");
474 }
475 if (!data_->saveToDisk()) {
476 return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
477 "Error saving data");
478 }
479 return Status::ok();
480}
481
482Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
483 const vector<AuthKeyData>& authKeyDatas = data_->getAuthKeyDatas();
484 vector<int32_t> ret;
485 for (const AuthKeyData& authKeyData : authKeyDatas) {
486 ret.push_back(authKeyData.useCount);
487 }
488 *_aidl_return = ret;
489 return Status::ok();
490}
491
492} // namespace identity
493} // namespace security
494} // namespace android