Add credstore system daemon.
The credstore system daemon is sitting below the Identity Credential
Framework APIs and on top of the Identity Credential HALs. Its main
job is to store credential data and provide a way for applications to
communicate with the secure hardware abstracted by the HAL.
This daemon runs as an unprivileged user, credstore.
The auth-tokens needed by credstore are supplied by keystore and this
CL includes the requisite changes to keystore for this to work.
Bug: 111446262
Test: CTS tests for Framework APIs
Change-Id: Ieb4d59852a143482436a1c418c25ed96e25c0047
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
index 6bffa7c..5e6d572 100644
--- a/keystore/auth_token_table.cpp
+++ b/keystore/auth_token_table.cpp
@@ -173,6 +173,60 @@
return {OK, newest_match->token()};
}
+std::tuple<AuthTokenTable::Error, HardwareAuthToken>
+AuthTokenTable::FindAuthorizationForCredstore(uint64_t challenge, uint64_t secureUserId,
+ int64_t authTokenMaxAgeMillis) {
+ std::vector<uint64_t> sids = {secureUserId};
+ HardwareAuthenticatorType auth_type = HardwareAuthenticatorType::ANY;
+
+ time_t now = clock_function_();
+
+ // challenge-based - the authToken has to contain the given challenge.
+ if (challenge != 0) {
+ auto matching_op = find_if(
+ entries_, [&](Entry& e) { return e.token().challenge == challenge && !e.completed(); });
+ if (matching_op == entries_.end()) {
+ return {AUTH_TOKEN_NOT_FOUND, {}};
+ }
+
+ if (!matching_op->SatisfiesAuth(sids, auth_type)) {
+ return {AUTH_TOKEN_WRONG_SID, {}};
+ }
+
+ if (authTokenMaxAgeMillis > 0) {
+ if (static_cast<int64_t>(matching_op->time_received()) + authTokenMaxAgeMillis <
+ static_cast<int64_t>(now)) {
+ return {AUTH_TOKEN_EXPIRED, {}};
+ }
+ }
+
+ return {OK, matching_op->token()};
+ }
+
+ // Otherwise, no challenge - any authToken younger than the specified maximum
+ // age will do.
+ Entry* newest_match = nullptr;
+ for (auto& entry : entries_) {
+ if (entry.SatisfiesAuth(sids, auth_type) && entry.is_newer_than(newest_match)) {
+ newest_match = &entry;
+ }
+ }
+
+ if (newest_match == nullptr) {
+ return {AUTH_TOKEN_NOT_FOUND, {}};
+ }
+
+ if (authTokenMaxAgeMillis > 0) {
+ if (static_cast<int64_t>(newest_match->time_received()) + authTokenMaxAgeMillis <
+ static_cast<int64_t>(now)) {
+ return {AUTH_TOKEN_EXPIRED, {}};
+ }
+ }
+
+ newest_match->UpdateLastUse(now);
+ return {OK, newest_match->token()};
+}
+
void AuthTokenTable::ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids) {
assert(sids);
for (auto& param : key_info)
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
index 7b48a6c..86d65de 100644
--- a/keystore/auth_token_table.h
+++ b/keystore/auth_token_table.h
@@ -76,6 +76,10 @@
std::tuple<Error, HardwareAuthToken> FindAuthorization(const AuthorizationSet& key_info,
KeyPurpose purpose, uint64_t op_handle);
+ std::tuple<Error, HardwareAuthToken>
+ FindAuthorizationForCredstore(uint64_t challenge, uint64_t secureUserId,
+ int64_t authTokenMaxAgeMillis);
+
/**
* Mark operation completed. This allows tokens associated with the specified operation to be
* superseded by new tokens.
diff --git a/keystore/binder/android/security/keystore/IKeystoreService.aidl b/keystore/binder/android/security/keystore/IKeystoreService.aidl
index f230043..fcea115 100644
--- a/keystore/binder/android/security/keystore/IKeystoreService.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreService.aidl
@@ -84,4 +84,7 @@
boolean isConfirmationPromptSupported();
int onKeyguardVisibilityChanged(in boolean isShowing, in int userId);
int listUidsOfAuthBoundKeys(out @utf8InCpp List<String> uids);
+
+ // Called by credstore (and only credstore).
+ byte[] getAuthTokenForCredstore(in long challenge, in long secureUserId, in int authTokenMaxAgeMillis);
}
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index 5adc199..5bc5a78 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -38,6 +38,7 @@
#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
+#include <keymasterV4_0/keymaster_utils.h>
#include "defaults.h"
#include "key_proto_handler.h"
@@ -946,6 +947,24 @@
return Status::ok();
}
+Status KeyStoreService::getAuthTokenForCredstore(int64_t challenge, int64_t secureUserId,
+ int32_t authTokenMaxAgeMillis,
+ std::vector<uint8_t>* _aidl_return) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (callingUid != AID_CREDSTORE) {
+ return Status::fromServiceSpecificError(static_cast<int32_t>(0));
+ }
+
+ auto [err, authToken] = mKeyStore->getAuthTokenTable().FindAuthorizationForCredstore(
+ challenge, secureUserId, authTokenMaxAgeMillis);
+ std::vector<uint8_t> ret;
+ if (err == AuthTokenTable::OK) {
+ ret = android::hardware::keymaster::V4_0::support::authToken2HidlVec(authToken);
+ }
+ *_aidl_return = ret;
+ return Status::ok();
+}
+
bool isDeviceIdAttestationRequested(const KeymasterArguments& params) {
const hardware::hidl_vec<KeyParameter>& paramsVec = params.getParameters();
for (size_t i = 0; i < paramsVec.size(); ++i) {
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index a395e6c..8c1d508 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -132,6 +132,9 @@
const ::android::sp<::android::IBinder>& token, int32_t* _aidl_return) override;
::android::binder::Status addAuthToken(const ::std::vector<uint8_t>& authToken,
int32_t* _aidl_return) override;
+ ::android::binder::Status
+ getAuthTokenForCredstore(int64_t challenge, int64_t secureUserId, int32_t authTokenMaxAge,
+ ::std::vector<uint8_t>* _aidl_return) override;
::android::binder::Status onUserAdded(int32_t userId, int32_t parentId,
int32_t* _aidl_return) override;
::android::binder::Status onUserRemoved(int32_t userId, int32_t* _aidl_return) override;