Merge "Remove use of size_t in Rust code"
diff --git a/fsverity_init/main.cpp b/fsverity_init/main.cpp
index 3f75dca..b502b91 100644
--- a/fsverity_init/main.cpp
+++ b/fsverity_init/main.cpp
@@ -48,12 +48,6 @@
return -1;
}
} else if (command == "--lock") {
- // Requires files backed by fs-verity to be verified with a key in .fs-verity
- // keyring.
- if (!android::base::WriteStringToFile("1", "/proc/sys/fs/verity/require_signatures")) {
- PLOG(ERROR) << "Failed to enforce fs-verity signature";
- }
-
if (!android::base::GetBoolProperty("ro.debuggable", false)) {
if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
PLOG(ERROR) << "Cannot restrict .fs-verity keyring";
diff --git a/identity/Android.bp b/identity/Android.bp
index 9117b7f..7b81685 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -32,35 +32,39 @@
],
srcs: [
- "main.cpp",
- "CredentialStore.cpp",
- "CredentialStoreFactory.cpp",
- "WritableCredential.cpp",
"Credential.cpp",
"CredentialData.cpp",
+ "CredentialStore.cpp",
+ "CredentialStoreFactory.cpp",
+ "RemotelyProvisionedKey.cpp",
"Session.cpp",
"Util.cpp",
+ "WritableCredential.cpp",
+ "main.cpp",
],
init_rc: ["credstore.rc"],
shared_libs: [
+ "android.hardware.identity-support-lib",
+ "android.hardware.keymaster@4.0",
+ "android.security.authorization-ndk",
+ "android.security.remoteprovisioning-cpp",
"libbase",
"libbinder",
"libbinder_ndk",
- "android.hardware.keymaster@4.0",
"libcredstore_aidl",
"libcrypto",
- "libutils",
"libhidlbase",
- "android.hardware.identity-support-lib",
"libkeymaster4support",
"libkeystore-attestation-application-id",
- "android.security.authorization-ndk",
- "android.security.remoteprovisioning-cpp",
+ "libutils",
"libutilscallstack",
+ "libvintf",
+ "server_configurable_flags",
],
static_libs: [
"android.hardware.security.rkp-V3-cpp",
"android.hardware.keymaster-V3-cpp",
+ "android.security.rkp_aidl-cpp",
"libcppbor_external",
],
}
diff --git a/identity/Credential.cpp b/identity/Credential.cpp
index c67fe4a..0b1d171 100644
--- a/identity/Credential.cpp
+++ b/identity/Credential.cpp
@@ -554,9 +554,18 @@
ret.resultNamespaces.push_back(resultNamespaceParcel);
}
- status = halBinder->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
- if (!status.isOk()) {
- return halStatusToGenericError(status);
+ // API version 5 (feature version 202301) supports both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ status = halBinder->finishRetrievalWithSignature(&ret.mac, &ret.deviceNameSpaces,
+ &ret.signature);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+ } else {
+ status = halBinder->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
}
ret.staticAuthenticationData = selectedAuthKeyStaticAuthData_;
@@ -694,7 +703,8 @@
return Status::ok();
}
-Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
+Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey,
+ int64_t minValidTimeMillis) {
if (halSessionBinder_) {
return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
"Cannot be used with session");
@@ -706,7 +716,7 @@
return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
"Error loading data for credential");
}
- data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+ data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, minValidTimeMillis);
if (!data->saveToDisk()) {
return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
"Error saving data");
@@ -777,11 +787,6 @@
Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
int64_t expirationDateMillisSinceEpoch,
const vector<uint8_t>& staticAuthData) {
- if (halApiVersion_ < 3) {
- return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
- "Not implemented by HAL");
- }
-
if (halSessionBinder_) {
return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
"Cannot be used with session");
@@ -828,6 +833,29 @@
return Status::ok();
}
+Status Credential::getAuthenticationDataExpirations(vector<int64_t>* _aidl_return) {
+ if (halSessionBinder_) {
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Cannot be used with session");
+ }
+
+ sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+ if (!data->loadFromDisk()) {
+ LOG(ERROR) << "Error loading data for credential";
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Error loading data for credential");
+ }
+ const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
+ vector<int64_t> ret;
+ ret.reserve(authKeyDatas.size());
+ for (const AuthKeyData& authKeyData : authKeyDatas) {
+ // Note: value is INT64_MAX if expiration date is not set.
+ ret.push_back(authKeyData.expirationDateMillisSinceEpoch);
+ }
+ *_aidl_return = ret;
+ return Status::ok();
+}
+
optional<string> extractDocType(const vector<uint8_t>& credentialData) {
auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
if (item == nullptr) {
@@ -887,8 +915,8 @@
dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
writableCredential->setAttestationCertificate(data->getAttestationCertificate());
- auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
- writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+ auto [keyCount, maxUsesPerKey, minValidTimeMillis] = data->getAvailableAuthenticationKeys();
+ writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, minValidTimeMillis);
// Because its data has changed, we need to replace the binder for the
// IIdentityCredential when the credential has been updated... otherwise the
diff --git a/identity/Credential.h b/identity/Credential.h
index 0906fea..4ecf92e 100644
--- a/identity/Credential.h
+++ b/identity/Credential.h
@@ -78,7 +78,8 @@
bool allowUsingExpiredKeys, bool incrementUsageCount,
GetEntriesResultParcel* _aidl_return) override;
- Status setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) override;
+ Status setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey,
+ int64_t minValidTimeMillis) override;
Status getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) override;
Status storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
const vector<uint8_t>& staticAuthData) override;
@@ -87,6 +88,7 @@
int64_t expirationDateMillisSinceEpoch,
const vector<uint8_t>& staticAuthData) override;
Status getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) override;
+ Status getAuthenticationDataExpirations(vector<int64_t>* _aidl_return) override;
Status update(sp<IWritableCredential>* _aidl_return) override;
diff --git a/identity/CredentialData.cpp b/identity/CredentialData.cpp
index 2189f90..fb08333 100644
--- a/identity/CredentialData.cpp
+++ b/identity/CredentialData.cpp
@@ -117,6 +117,7 @@
map.add("entryData", std::move(encryptedBlobsMap));
map.add("authKeyCount", keyCount_);
map.add("maxUsesPerAuthKey", maxUsesPerKey_);
+ map.add("minValidTimeMillis", minValidTimeMillis_);
cppbor::Array authKeyDatasArray;
for (const AuthKeyData& data : authKeyDatas_) {
@@ -253,6 +254,7 @@
authKeyDatas_.clear();
keyCount_ = 0;
maxUsesPerKey_ = 1;
+ minValidTimeMillis_ = 0;
optional<vector<uint8_t>> data = fileGetContents(fileName_);
if (!data) {
@@ -398,6 +400,14 @@
return false;
}
maxUsesPerKey_ = number->value();
+
+ } else if (key == "minValidTimeMillis") {
+ const cppbor::Int* number = valueItem->asInt();
+ if (number == nullptr) {
+ LOG(ERROR) << "Value for minValidTimeMillis is not a number";
+ return false;
+ }
+ minValidTimeMillis_ = number->value();
}
}
@@ -479,9 +489,11 @@
// ---
-void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+ int64_t minValidTimeMillis) {
keyCount_ = keyCount;
maxUsesPerKey_ = maxUsesPerKey;
+ minValidTimeMillis_ = minValidTimeMillis;
// If growing the number of auth keys (prevKeyCount < keyCount_ case) we'll add
// new AuthKeyData structs to |authKeyDatas_| and each struct will have empty |certificate|
@@ -499,8 +511,9 @@
return authKeyDatas_;
}
-pair<int /* keyCount */, int /*maxUsersPerKey */> CredentialData::getAvailableAuthenticationKeys() {
- return std::make_pair(keyCount_, maxUsesPerKey_);
+tuple<int /* keyCount */, int /*maxUsersPerKey */, int64_t /* minValidTimeMillis */>
+CredentialData::getAvailableAuthenticationKeys() const {
+ return std::make_tuple(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
}
AuthKeyData* CredentialData::findAuthKey_(bool allowUsingExhaustedKeys,
@@ -573,9 +586,10 @@
for (AuthKeyData& data : authKeyDatas_) {
bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
- bool keyBeyondExpirationDate = (nowMilliSeconds > data.expirationDateMillisSinceEpoch);
+ int64_t expirationDateAdjusted = data.expirationDateMillisSinceEpoch - minValidTimeMillis_;
+ bool keyBeyondAdjustedExpirationDate = (nowMilliSeconds > expirationDateAdjusted);
bool newKeyNeeded =
- (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondExpirationDate;
+ (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondAdjustedExpirationDate;
bool certificationPending = (data.pendingCertificate.size() > 0);
if (newKeyNeeded && !certificationPending) {
vector<uint8_t> signingKeyBlob;
diff --git a/identity/CredentialData.h b/identity/CredentialData.h
index e240e47..3f7cd3a 100644
--- a/identity/CredentialData.h
+++ b/identity/CredentialData.h
@@ -37,7 +37,6 @@
using ::android::hardware::identity::SecureAccessControlProfile;
using ::std::map;
using ::std::optional;
-using ::std::pair;
using ::std::string;
using ::std::tuple;
using ::std::vector;
@@ -89,7 +88,8 @@
bool deleteCredential();
- void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+ void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+ int64_t minValidTimeMillis);
// Getters
@@ -107,7 +107,8 @@
const vector<AuthKeyData>& getAuthKeyDatas() const;
- pair<int /* keyCount */, int /*maxUsersPerKey */> getAvailableAuthenticationKeys();
+ tuple<int /* keyCount */, int /*maxUsersPerKey */, int64_t /* minValidTimeMillis */>
+ getAvailableAuthenticationKeys() const;
// Returns |nullptr| if a suitable key cannot be found. Otherwise returns
// the authentication and increases its use-count.
@@ -143,6 +144,7 @@
int keyCount_ = 0;
int maxUsesPerKey_ = 1;
+ int64_t minValidTimeMillis_ = 0;
vector<AuthKeyData> authKeyDatas_; // Always |keyCount_| long.
};
diff --git a/identity/CredentialStore.cpp b/identity/CredentialStore.cpp
index c5c429b..eb9bdb6 100644
--- a/identity/CredentialStore.cpp
+++ b/identity/CredentialStore.cpp
@@ -26,6 +26,8 @@
#include <android/security/remoteprovisioning/RemotelyProvisionedKey.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <server_configurable_flags/get_flags.h>
+#include <vintf/VintfObject.h>
#include "Credential.h"
#include "CredentialData.h"
@@ -39,41 +41,14 @@
namespace identity {
namespace {
-using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
-using ::android::hardware::security::keymint::RpcHardwareInfo;
using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
-using ::android::security::remoteprovisioning::RemotelyProvisionedKey;
+using ::android::security::rkp::IRemoteProvisioning;
-std::optional<std::string>
-getRemotelyProvisionedComponentId(const sp<IIdentityCredentialStore>& hal) {
- auto init = [](const sp<IIdentityCredentialStore>& hal) -> std::optional<std::string> {
- sp<IRemotelyProvisionedComponent> remotelyProvisionedComponent;
- Status status = hal->getRemotelyProvisionedComponent(&remotelyProvisionedComponent);
- if (!status.isOk()) {
- LOG(ERROR) << "Error getting remotely provisioned component: " << status;
- return std::nullopt;
- }
-
- RpcHardwareInfo rpcHwInfo;
- status = remotelyProvisionedComponent->getHardwareInfo(&rpcHwInfo);
- if (!status.isOk()) {
- LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
- return std::nullopt;
- }
-
- if (!rpcHwInfo.uniqueId) {
- LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
- << "required for credential key remotely provisioned attestation keys. "
- << "This is a bug in the vendor implementation.";
- return std::nullopt;
- }
-
- // This id is required to later fetch remotely provisioned attestation keys.
- return *rpcHwInfo.uniqueId;
- };
-
- static std::optional<std::string> id = init(hal);
- return id;
+bool useRkpd() {
+ std::string useRkpdFlagValue = server_configurable_flags::GetServerConfigurableFlag(
+ "remote_key_provisioning_native", "enable_rkpd",
+ /*default_value=*/"false");
+ return useRkpdFlagValue == "true";
}
} // namespace
@@ -90,13 +65,30 @@
halApiVersion_ = hal_->getInterfaceVersion();
if (hwInfo_.isRemoteKeyProvisioningSupported) {
- keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
- IRemotelyProvisionedKeyPool::descriptor);
- if (keyPool_.get() == nullptr) {
- LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
- << IRemotelyProvisionedKeyPool::descriptor << "'";
+ status = hal_->getRemotelyProvisionedComponent(&rpc_);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Error getting remotely provisioned component: " << status;
return false;
}
+ useRkpd_ = useRkpd();
+
+ if (useRkpd_) {
+ uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+ auto rpcKeyFuture = getRpcKeyFuture(rpc_, callingUid);
+ if (!rpcKeyFuture) {
+ LOG(ERROR) << "Error in getRpcKeyFuture()";
+ return false;
+ }
+ rpcKeyFuture_ = std::move(*rpcKeyFuture);
+ } else {
+ keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
+ IRemotelyProvisionedKeyPool::descriptor);
+ if (!keyPool_) {
+ LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
+ << IRemotelyProvisionedKeyPool::descriptor << "'";
+ return false;
+ }
+ }
}
LOG(INFO) << "Connected to Identity Credential HAL with API version " << halApiVersion_
@@ -209,28 +201,54 @@
Status CredentialStore::setRemotelyProvisionedAttestationKey(
IWritableIdentityCredential* halWritableCredential) {
- std::optional<std::string> rpcId = getRemotelyProvisionedComponentId(hal_);
- if (!rpcId) {
- return Status::fromServiceSpecificError(ERROR_GENERIC,
- "Error getting remotely provisioned component id");
+ std::vector<uint8_t> keyBlob;
+ std::vector<uint8_t> encodedCertChain;
+ Status status;
+
+ if (useRkpd_) {
+ if (rpcKeyFuture_.wait_for(std::chrono::seconds(10)) != std::future_status::ready) {
+ return Status::fromServiceSpecificError(
+ ERROR_GENERIC, "Waiting for remotely provisioned attestation key timed out");
+ }
+
+ std::optional<::android::security::rkp::RemotelyProvisionedKey> key = rpcKeyFuture_.get();
+ if (!key) {
+ return Status::fromServiceSpecificError(
+ ERROR_GENERIC, "Failed to get remotely provisioned attestation key");
+ }
+
+ if (key->keyBlob.empty()) {
+ return Status::fromServiceSpecificError(
+ ERROR_GENERIC, "Remotely provisioned attestation key blob is empty");
+ }
+
+ keyBlob = std::move(key->keyBlob);
+ encodedCertChain = std::move(key->encodedCertChain);
+ } else {
+ std::optional<std::string> rpcId = getRpcId(rpc_);
+ if (!rpcId) {
+ return Status::fromServiceSpecificError(
+ ERROR_GENERIC, "Error getting remotely provisioned component id");
+ }
+
+ uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+ ::android::security::remoteprovisioning::RemotelyProvisionedKey key;
+ Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
+ if (!status.isOk()) {
+ LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
+ << "to the factory-provisioned attestation key.";
+ return Status::ok();
+ }
+
+ keyBlob = std::move(key.keyBlob);
+ encodedCertChain = std::move(key.encodedCertChain);
}
- uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
- RemotelyProvisionedKey key;
- Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
- if (!status.isOk()) {
- LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
- << "to the factory-provisioned attestation key.";
- return Status::ok();
- }
-
- status = halWritableCredential->setRemotelyProvisionedAttestationKey(key.keyBlob,
- key.encodedCertChain);
+ status = halWritableCredential->setRemotelyProvisionedAttestationKey(keyBlob, encodedCertChain);
if (!status.isOk()) {
LOG(ERROR) << "Error setting remotely provisioned attestation key on credential";
return status;
}
-
return Status::ok();
}
diff --git a/identity/CredentialStore.h b/identity/CredentialStore.h
index df7928e..495841b 100644
--- a/identity/CredentialStore.h
+++ b/identity/CredentialStore.h
@@ -17,12 +17,16 @@
#ifndef SYSTEM_SECURITY_CREDENTIAL_STORE_H_
#define SYSTEM_SECURITY_CREDENTIAL_STORE_H_
+#include <future>
#include <string>
#include <vector>
#include <android/hardware/identity/IIdentityCredentialStore.h>
#include <android/security/identity/BnCredentialStore.h>
#include <android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+
+#include "RemotelyProvisionedKey.h"
namespace android {
namespace security {
@@ -39,6 +43,7 @@
using ::android::hardware::identity::IIdentityCredentialStore;
using ::android::hardware::identity::IPresentationSession;
using ::android::hardware::identity::IWritableIdentityCredential;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
class CredentialStore : public BnCredentialStore {
@@ -73,9 +78,12 @@
sp<IIdentityCredentialStore> hal_;
int halApiVersion_;
- sp<IRemotelyProvisionedKeyPool> keyPool_;
-
HardwareInformation hwInfo_;
+
+ bool useRkpd_;
+ sp<IRemotelyProvisionedComponent> rpc_;
+ sp<IRemotelyProvisionedKeyPool> keyPool_;
+ std::future<std::optional<RemotelyProvisionedKey>> rpcKeyFuture_;
};
} // namespace identity
diff --git a/identity/RemotelyProvisionedKey.cpp b/identity/RemotelyProvisionedKey.cpp
new file mode 100644
index 0000000..46a42f4
--- /dev/null
+++ b/identity/RemotelyProvisionedKey.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "credstore"
+
+#include <atomic>
+
+#include <android-base/logging.h>
+#include <android/security/rkp/BnGetKeyCallback.h>
+#include <android/security/rkp/BnGetRegistrationCallback.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <vintf/VintfObject.h>
+
+#include "RemotelyProvisionedKey.h"
+
+namespace android {
+namespace security {
+namespace identity {
+namespace {
+
+using ::android::binder::Status;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::hardware::security::keymint::RpcHardwareInfo;
+using ::android::security::rkp::BnGetKeyCallback;
+using ::android::security::rkp::BnGetRegistrationCallback;
+using ::android::security::rkp::IRegistration;
+using ::android::security::rkp::IRemoteProvisioning;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+std::optional<String16> findRpcNameById(std::string_view targetRpcId) {
+ auto deviceManifest = vintf::VintfObject::GetDeviceHalManifest();
+ auto instances = deviceManifest->getAidlInstances("android.hardware.security.keymint",
+ "IRemotelyProvisionedComponent");
+ for (const std::string& instance : instances) {
+ auto rpcName =
+ IRemotelyProvisionedComponent::descriptor + String16("/") + String16(instance.c_str());
+ sp<IRemotelyProvisionedComponent> rpc =
+ android::waitForService<IRemotelyProvisionedComponent>(rpcName);
+
+ auto rpcId = getRpcId(rpc);
+ if (!rpcId) {
+ continue;
+ }
+ if (*rpcId == targetRpcId) {
+ return rpcName;
+ }
+ }
+
+ LOG(ERROR) << "Remotely provisioned component with given unique ID: " << targetRpcId
+ << " not found";
+ return std::nullopt;
+}
+
+std::optional<String16> getRpcName(const sp<IRemotelyProvisionedComponent>& rpc) {
+ std::optional<std::string> targetRpcId = getRpcId(rpc);
+ if (!targetRpcId) {
+ return std::nullopt;
+ }
+ return findRpcNameById(*targetRpcId);
+}
+
+class GetKeyCallback : public BnGetKeyCallback {
+ public:
+ GetKeyCallback(std::promise<std::optional<RemotelyProvisionedKey>> keyPromise)
+ : keyPromise_(std::move(keyPromise)), called_() {}
+
+ Status onSuccess(const RemotelyProvisionedKey& key) override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ keyPromise_.set_value(key);
+ return Status::ok();
+ }
+ Status onCancel() override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ LOG(ERROR) << "GetKeyCallback cancelled";
+ keyPromise_.set_value(std::nullopt);
+ return Status::ok();
+ }
+ Status onError(const String16& error) override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ LOG(ERROR) << "GetKeyCallback failed: " << error;
+ keyPromise_.set_value(std::nullopt);
+ return Status::ok();
+ }
+
+ private:
+ std::promise<std::optional<RemotelyProvisionedKey>> keyPromise_;
+ // This callback can only be called into once
+ std::atomic_flag called_;
+};
+
+class GetRegistrationCallback : public BnGetRegistrationCallback {
+ public:
+ GetRegistrationCallback(std::promise<std::optional<RemotelyProvisionedKey>> keyPromise,
+ uint32_t keyId)
+ : keyPromise_(std::move(keyPromise)), keyId_(keyId), called_() {}
+
+ Status onSuccess(const sp<IRegistration>& registration) override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ auto cb = sp<GetKeyCallback>::make(std::move(keyPromise_));
+ auto status = registration->getKey(keyId_, cb);
+ if (!status.isOk()) {
+ cb->onError(String16("Failed to register GetKeyCallback"));
+ }
+ return Status::ok();
+ }
+ Status onCancel() override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ LOG(ERROR) << "GetRegistrationCallback cancelled";
+ keyPromise_.set_value(std::nullopt);
+ return Status::ok();
+ }
+ Status onError(const String16& error) override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ LOG(ERROR) << "GetRegistrationCallback failed: " << error;
+ keyPromise_.set_value(std::nullopt);
+ return Status::ok();
+ }
+
+ private:
+ std::promise<std::optional<RemotelyProvisionedKey>> keyPromise_;
+ int32_t keyId_;
+ // This callback can only be called into once
+ std::atomic_flag called_;
+};
+
+} // namespace
+
+std::optional<std::string> getRpcId(const sp<IRemotelyProvisionedComponent>& rpc) {
+ RpcHardwareInfo rpcHwInfo;
+ Status status = rpc->getHardwareInfo(&rpcHwInfo);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
+ return std::nullopt;
+ }
+
+ if (!rpcHwInfo.uniqueId) {
+ LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
+ << "required for credential key remotely provisioned attestation keys. "
+ << "This is a bug in the vendor implementation.";
+ return std::nullopt;
+ }
+
+ return *rpcHwInfo.uniqueId;
+}
+
+std::optional<std::future<std::optional<RemotelyProvisionedKey>>>
+getRpcKeyFuture(const sp<IRemotelyProvisionedComponent>& rpc, int32_t keyId) {
+ std::promise<std::optional<RemotelyProvisionedKey>> keyPromise;
+ auto keyFuture = keyPromise.get_future();
+
+ auto rpcName = getRpcName(rpc);
+ if (!rpcName) {
+ LOG(ERROR) << "Failed to get IRemotelyProvisionedComponent name";
+ return std::nullopt;
+ }
+
+ sp<IRemoteProvisioning> remoteProvisioning =
+ android::waitForService<IRemoteProvisioning>(IRemoteProvisioning::descriptor);
+ if (!remoteProvisioning) {
+ LOG(ERROR) << "Failed to get IRemoteProvisioning HAL";
+ return std::nullopt;
+ }
+
+ auto cb = sp<GetRegistrationCallback>::make(std::move(keyPromise), keyId);
+ Status status = remoteProvisioning->getRegistration(*rpcName, cb);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Failed getRegistration()";
+ return std::nullopt;
+ }
+
+ return keyFuture;
+}
+
+} // namespace identity
+} // namespace security
+} // namespace android
diff --git a/identity/RemotelyProvisionedKey.h b/identity/RemotelyProvisionedKey.h
new file mode 100644
index 0000000..e7ddfca
--- /dev/null
+++ b/identity/RemotelyProvisionedKey.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <future>
+#include <optional>
+
+#include <android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+std::optional<std::string> getRpcId(const sp<IRemotelyProvisionedComponent>& rpc);
+
+std::optional<std::future<std::optional<RemotelyProvisionedKey>>>
+getRpcKeyFuture(const sp<IRemotelyProvisionedComponent>& rpc, int32_t keyId);
+
+} // namespace identity
+} // namespace security
+} // namespace android
diff --git a/identity/WritableCredential.cpp b/identity/WritableCredential.cpp
index 9827d75..d863494 100644
--- a/identity/WritableCredential.cpp
+++ b/identity/WritableCredential.cpp
@@ -101,9 +101,11 @@
attestationCertificate_ = attestationCertificate;
}
-void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+ int64_t minValidTimeMillis) {
keyCount_ = keyCount;
maxUsesPerKey_ = maxUsesPerKey;
+ minValidTimeMillis_ = minValidTimeMillis;
}
ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
@@ -260,7 +262,7 @@
}
data.setCredentialData(credentialData);
- data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_);
+ data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
if (!data.saveToDisk()) {
return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
diff --git a/identity/WritableCredential.h b/identity/WritableCredential.h
index 838b956..c92d58a 100644
--- a/identity/WritableCredential.h
+++ b/identity/WritableCredential.h
@@ -45,7 +45,8 @@
// Used when updating a credential
void setAttestationCertificate(const vector<uint8_t>& attestationCertificate);
- void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+ void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+ int64_t minValidTimeMillis);
// Used by Credential::update()
void setCredentialToReloadWhenUpdated(sp<Credential> credential);
@@ -69,6 +70,7 @@
vector<uint8_t> attestationCertificate_;
int keyCount_ = 0;
int maxUsesPerKey_ = 1;
+ int64_t minValidTimeMillis_ = 0;
sp<Credential> credentialToReloadWhenUpdated_;
diff --git a/identity/binder/android/security/identity/GetEntriesResultParcel.aidl b/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
index 03b363c..51281b9 100644
--- a/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
+++ b/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
@@ -26,4 +26,5 @@
byte[] deviceNameSpaces;
byte[] mac;
byte[] staticAuthenticationData;
+ byte[] signature; // Added in Android 14 / U
}
diff --git a/identity/binder/android/security/identity/ICredential.aidl b/identity/binder/android/security/identity/ICredential.aidl
index e6a9fae..875b934 100644
--- a/identity/binder/android/security/identity/ICredential.aidl
+++ b/identity/binder/android/security/identity/ICredential.aidl
@@ -60,7 +60,9 @@
in boolean allowUsingExpiredKeys,
in boolean incrementUsageCount);
- void setAvailableAuthenticationKeys(in int keyCount, in int maxUsesPerKey);
+ void setAvailableAuthenticationKeys(in int keyCount,
+ in int maxUsesPerKey,
+ in long minValidTimeMillis);
AuthKeyParcel[] getAuthKeysNeedingCertification();
@@ -73,6 +75,8 @@
int[] getAuthenticationDataUsageCount();
+ long[] getAuthenticationDataExpirations();
+
IWritableCredential update();
}
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 51ce9d1..fa80563 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -41,8 +41,10 @@
"android.security.maintenance-rust",
"android.security.metrics-rust",
"android.security.remoteprovisioning-rust",
+ "android.security.rkp_aidl-rust",
"libanyhow",
"libbinder_rs",
+ "libfutures",
"libkeystore2_aaid-rust",
"libkeystore2_apc_compat-rust",
"libkeystore2_crypto_rust",
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index 1e6d4dc..e3961da 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -128,7 +128,7 @@
name: "android.security.maintenance",
srcs: [ "android/security/maintenance/*.aidl" ],
imports: [
- "android.system.keystore2-V2",
+ "android.system.keystore2-V3",
],
unstable: true,
backend: {
@@ -167,7 +167,7 @@
name: "android.security.metrics",
srcs: [ "android/security/metrics/*.aidl" ],
imports: [
- "android.system.keystore2-V2",
+ "android.system.keystore2-V3",
],
unstable: true,
backend: {
@@ -184,29 +184,68 @@
},
}
+// java_defaults that includes the latest Keystore2 AIDL library.
+// Modules that depend on KeyMint directly can include this java_defaults to avoid
+// managing dependency versions explicitly.
+java_defaults {
+ name: "keystore2_use_latest_aidl_java_static",
+ static_libs: [
+ "android.system.keystore2-V3-java-source"
+ ],
+}
+
+java_defaults {
+ name: "keystore2_use_latest_aidl_java_shared",
+ libs: [
+ "android.system.keystore2-V3-java-source"
+ ],
+}
+
+java_defaults {
+ name: "keystore2_use_latest_aidl_java",
+ libs: [
+ "android.system.keystore2-V3-java"
+ ],
+}
+
// cc_defaults that includes the latest Keystore2 AIDL library.
// Modules that depend on KeyMint directly can include this cc_defaults to avoid
// managing dependency versions explicitly.
cc_defaults {
name: "keystore2_use_latest_aidl_ndk_static",
static_libs: [
- "android.system.keystore2-V2-ndk",
+ "android.system.keystore2-V3-ndk",
],
}
cc_defaults {
name: "keystore2_use_latest_aidl_ndk_shared",
shared_libs: [
- "android.system.keystore2-V2-ndk",
+ "android.system.keystore2-V3-ndk",
],
}
+cc_defaults {
+ name: "keystore2_use_latest_aidl_cpp_shared",
+ shared_libs: [
+ "android.system.keystore2-V3-cpp",
+ ],
+}
+
+cc_defaults {
+ name: "keystore2_use_latest_aidl_cpp_static",
+ static_libs: [
+ "android.system.keystore2-V3-cpp",
+ ],
+}
+
+
// A rust_defaults that includes the latest Keystore2 AIDL library.
// Modules that depend on Keystore2 directly can include this rust_defaults to avoid
// managing dependency versions explicitly.
rust_defaults {
name: "keystore2_use_latest_aidl_rust",
rustlibs: [
- "android.system.keystore2-V2-rust",
+ "android.system.keystore2-V3-rust",
],
}
diff --git a/keystore2/android.system.keystore2-service.xml b/keystore2/android.system.keystore2-service.xml
index 20c2fba..45f995c 100644
--- a/keystore2/android.system.keystore2-service.xml
+++ b/keystore2/android.system.keystore2-service.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="framework">
<hal format="aidl">
<name>android.system.keystore2</name>
- <version>2</version>
+ <version>3</version>
<interface>
<name>IKeystoreService</name>
<instance>default</instance>
diff --git a/keystore2/src/attestation_key_utils.rs b/keystore2/src/attestation_key_utils.rs
index 94f3e4c..d01cf86 100644
--- a/keystore2/src/attestation_key_utils.rs
+++ b/keystore2/src/attestation_key_utils.rs
@@ -40,6 +40,10 @@
attestation_key: AttestationKey,
attestation_certs: Certificate,
},
+ RkpdProvisioned {
+ attestation_key: AttestationKey,
+ attestation_certs: Certificate,
+ },
UserGenerated {
key_id_guard: KeyIdGuard,
blob: Vec<u8>,
@@ -48,6 +52,12 @@
},
}
+fn use_rkpd() -> bool {
+ let property_name = "persist.device_config.remote_key_provisioning_native.enable_rkpd";
+ let default_value = false;
+ rustutils::system_properties::read_bool(property_name, default_value).unwrap_or(default_value)
+}
+
/// This function loads and, optionally, assigns the caller's remote provisioned
/// attestation key if a challenge is present. Alternatively, if `attest_key_descriptor` is given,
/// it loads the user generated attestation key from the database.
@@ -64,18 +74,34 @@
params.iter().any(|kp| kp.tag == Tag::DEVICE_UNIQUE_ATTESTATION);
match attest_key_descriptor {
// Do not select an RKP key if DEVICE_UNIQUE_ATTESTATION is present.
- None if challenge_present && !is_device_unique_attestation => rem_prov_state
- .get_remotely_provisioned_attestation_key_and_certs(key, caller_uid, params, db)
- .context(ks_err!("Trying to get remotely provisioned attestation key."))
- .map(|result| {
- result.map(|(key_id_guard, attestation_key, attestation_certs)| {
- AttestationKeyInfo::RemoteProvisioned {
- key_id_guard,
- attestation_key,
- attestation_certs,
- }
- })
- }),
+ None if challenge_present && !is_device_unique_attestation => {
+ if use_rkpd() {
+ rem_prov_state
+ .get_rkpd_attestation_key_and_certs(key, caller_uid, params)
+ .context(ks_err!("Trying to get attestation key from RKPD."))
+ .map(|result| {
+ result.map(|(attestation_key, attestation_certs)| {
+ AttestationKeyInfo::RkpdProvisioned {
+ attestation_key,
+ attestation_certs,
+ }
+ })
+ })
+ } else {
+ rem_prov_state
+ .get_remotely_provisioned_attestation_key_and_certs(key, caller_uid, params, db)
+ .context(ks_err!("Trying to get remotely provisioned attestation key."))
+ .map(|result| {
+ result.map(|(key_id_guard, attestation_key, attestation_certs)| {
+ AttestationKeyInfo::RemoteProvisioned {
+ key_id_guard,
+ attestation_key,
+ attestation_certs,
+ }
+ })
+ })
+ }
+ }
None => Ok(None),
Some(attest_key) => get_user_generated_attestation_key(attest_key, caller_uid, db)
.context(ks_err!("Trying to load attest key"))
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index dbdb4e6..62fd579 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -5335,6 +5335,10 @@
SecurityLevel::TRUSTED_ENVIRONMENT,
),
KeyParameter::new(
+ KeyParameterValue::AttestationIdSecondIMEI(vec![4u8, 3u8, 1u8, 2u8]),
+ SecurityLevel::TRUSTED_ENVIRONMENT,
+ ),
+ KeyParameter::new(
KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
SecurityLevel::TRUSTED_ENVIRONMENT,
),
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 425812f..ed59578 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -441,13 +441,12 @@
static REMOTE_PROVISIONING_HAL_SERVICE_NAME: &str =
"android.hardware.security.keymint.IRemotelyProvisionedComponent";
-fn connect_remotely_provisioned_component(
- security_level: &SecurityLevel,
-) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
+/// Get the service name of a remotely provisioned component corresponding to given security level.
+pub fn get_remotely_provisioned_component_name(security_level: &SecurityLevel) -> Result<String> {
let remotely_prov_instances =
get_aidl_instances("android.hardware.security.keymint", 1, "IRemotelyProvisionedComponent");
- let service_name = match *security_level {
+ match *security_level {
SecurityLevel::TRUSTED_ENVIRONMENT => {
if remotely_prov_instances.iter().any(|instance| *instance == "default") {
Some(format!("{}/default", REMOTE_PROVISIONING_HAL_SERVICE_NAME))
@@ -465,8 +464,13 @@
_ => None,
}
.ok_or(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
- .context(ks_err!())?;
+ .context(ks_err!())
+}
+fn connect_remotely_provisioned_component(
+ security_level: &SecurityLevel,
+) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
+ let service_name = get_remotely_provisioned_component_name(security_level)?;
let rem_prov_hal: Strong<dyn IRemotelyProvisionedComponent> =
map_binder_status_code(binder::get_interface(&service_name))
.context(ks_err!("Trying to connect to RemotelyProvisionedComponent service."))?;
diff --git a/keystore2/src/key_parameter.rs b/keystore2/src/key_parameter.rs
index 9854974..b3dcf45 100644
--- a/keystore2/src/key_parameter.rs
+++ b/keystore2/src/key_parameter.rs
@@ -966,9 +966,12 @@
/// Provides the device's serial number, to attestKey()
#[key_param(tag = ATTESTATION_ID_SERIAL, field = Blob)]
AttestationIdSerial(Vec<u8>),
- /// Provides the IMEIs for all radios on the device, to attestKey()
+ /// Provides the primary IMEI for the device, to attestKey()
#[key_param(tag = ATTESTATION_ID_IMEI, field = Blob)]
AttestationIdIMEI(Vec<u8>),
+ /// Provides a second IMEI for the device, to attestKey()
+ #[key_param(tag = ATTESTATION_ID_SECOND_IMEI, field = Blob)]
+ AttestationIdSecondIMEI(Vec<u8>),
/// Provides the MEIDs for all radios on the device, to attestKey()
#[key_param(tag = ATTESTATION_ID_MEID, field = Blob)]
AttestationIdMEID(Vec<u8>),
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index c54753c..8c5bf0f 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -148,17 +148,20 @@
// Devices with KS2 and KM 1.0 may not have any IRemotelyProvisionedComponent HALs at all. Do
// not panic if new_native_binder returns failure because it could not find the TEE HAL.
- if let Ok(remote_provisioning_service) = RemoteProvisioningService::new_native_binder() {
- binder::add_service(
- REMOTE_PROVISIONING_SERVICE_NAME,
- remote_provisioning_service.as_binder(),
- )
- .unwrap_or_else(|e| {
- panic!(
- "Failed to register service {} because of {:?}.",
- REMOTE_PROVISIONING_SERVICE_NAME, e
- );
- });
+ match RemoteProvisioningService::new_native_binder() {
+ Ok(remote_provisioning_service) => {
+ binder::add_service(
+ REMOTE_PROVISIONING_SERVICE_NAME,
+ remote_provisioning_service.as_binder(),
+ )
+ .unwrap_or_else(|e| {
+ panic!(
+ "Failed to register service {} because of {:?}.",
+ REMOTE_PROVISIONING_SERVICE_NAME, e
+ );
+ });
+ }
+ Err(e) => log::info!("Not publishing {}: {:?}", REMOTE_PROVISIONING_SERVICE_NAME, e),
}
// Even if the IRemotelyProvisionedComponent HAL is implemented, it doesn't mean that the keys
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 13f7760..2632ec4 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -450,6 +450,10 @@
)));
assert!(sec_level_enforced.iter().any(|kp| matches!(
kp,
+ KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KeyParameterValue::Integer(_) }
+ )));
+ assert!(sec_level_enforced.iter().any(|kp| matches!(
+ kp,
KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KeyParameterValue::Integer(_) }
)));
}
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 0b830be..9794889 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -38,6 +38,7 @@
pub mod permission;
pub mod raw_device;
pub mod remote_provisioning;
+pub mod rkpd_client;
pub mod security_level;
pub mod service;
pub mod shared_secret_negotiation;
diff --git a/keystore2/src/raw_device.rs b/keystore2/src/raw_device.rs
index fe044ee..fa9872a 100644
--- a/keystore2/src/raw_device.rs
+++ b/keystore2/src/raw_device.rs
@@ -63,11 +63,13 @@
pub const KEY_MINT_V1: i32 = 100;
/// Version number of KeyMintDevice@V2
pub const KEY_MINT_V2: i32 = 200;
+ /// Version number of KeyMintDevice@V3
+ pub const KEY_MINT_V3: i32 = 300;
/// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
- let (km_dev, hw_info, km_uuid) = get_keymint_device(&security_level)
- .context("In KeyMintDevice::get: get_keymint_device failed")?;
+ let (km_dev, hw_info, km_uuid) =
+ get_keymint_device(&security_level).context(ks_err!("get_keymint_device failed"))?;
Ok(KeyMintDevice {
km_dev,
@@ -111,12 +113,11 @@
where
F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,
{
- let creation_result = map_km_error(creator(&self.km_dev))
- .context("In create_and_store_key: creator failed")?;
+ let creation_result =
+ map_km_error(creator(&self.km_dev)).context(ks_err!("creator failed"))?;
let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
- let creation_date =
- DateTime::now().context("In create_and_store_key: DateTime::now() failed")?;
+ let creation_date = DateTime::now().context(ks_err!("DateTime::now() failed"))?;
let mut key_metadata = KeyMetaData::new();
key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
@@ -132,7 +133,7 @@
&key_metadata,
&self.km_uuid,
)
- .context("In create_and_store_key: store_new_key failed")?;
+ .context(ks_err!("store_new_key failed"))?;
Ok(())
}
@@ -244,7 +245,7 @@
.take_key_blob_info()
.ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
.map(|(key_blob, _)| KeyBlob::NonSensitive(key_blob))
- .context("Missing key blob info.")?,
+ .context(ks_err!("Missing key blob info."))?,
))
})
.context(ks_err!("second lookup failed"))
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index fec1b92..cb2962a 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -53,6 +53,7 @@
use crate::ks_err;
use crate::metrics_store::log_rkp_error_stats;
use crate::permission::KeystorePerm;
+use crate::rkpd_client::get_rkpd_attestation_key;
use crate::utils::{check_keystore_permission, watchdog as wd};
use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
@@ -184,7 +185,47 @@
}
}
}
+
+ /// Fetches attestation key and corresponding certificates from RKPD.
+ pub fn get_rkpd_attestation_key_and_certs(
+ &self,
+ key: &KeyDescriptor,
+ caller_uid: u32,
+ params: &[KeyParameter],
+ ) -> Result<Option<(AttestationKey, Certificate)>> {
+ if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
+ Ok(None)
+ } else {
+ match get_rkpd_attestation_key(&self.security_level, caller_uid) {
+ Err(e) => {
+ if self.is_rkp_only() {
+ log::error!("Error occurred: {:?}", e);
+ return Err(e);
+ }
+ log::warn!("Error occurred: {:?}", e);
+ log_rkp_error_stats(
+ MetricsRkpError::FALL_BACK_DURING_HYBRID,
+ &self.security_level,
+ );
+ Ok(None)
+ }
+ Ok(rkpd_key) => Ok(Some((
+ AttestationKey {
+ keyBlob: rkpd_key.keyBlob,
+ attestKeyParams: vec![],
+ // Batch certificate is at the beginning of the certificate chain.
+ issuerSubjectName: parse_subject_from_certificate(
+ &rkpd_key.encodedCertChain,
+ )
+ .context(ks_err!("Failed to parse subject."))?,
+ },
+ Certificate { encodedCertificate: rkpd_key.encodedCertChain },
+ ))),
+ }
+ }
+ }
}
+
/// Implementation of the IRemoteProvisioning service.
#[derive(Default)]
pub struct RemoteProvisioningService {
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
new file mode 100644
index 0000000..2d1b23b
--- /dev/null
+++ b/keystore2/src/rkpd_client.rs
@@ -0,0 +1,387 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Helper wrapper around RKPD interface.
+
+use crate::error::{map_binder_status_code, map_or_log_err, Error, ErrorCode};
+use crate::globals::get_remotely_provisioned_component_name;
+use crate::ks_err;
+use crate::utils::watchdog as wd;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use android_security_rkp_aidl::aidl::android::security::rkp::{
+ IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::IGetKeyCallback,
+ IGetRegistrationCallback::BnGetRegistrationCallback,
+ IGetRegistrationCallback::IGetRegistrationCallback, IRegistration::IRegistration,
+ IRemoteProvisioning::IRemoteProvisioning, RemotelyProvisionedKey::RemotelyProvisionedKey,
+};
+use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
+use anyhow::{Context, Result};
+use futures::channel::oneshot;
+use futures::executor::block_on;
+use std::sync::Mutex;
+
+type RegistrationSender = oneshot::Sender<Result<binder::Strong<dyn IRegistration>>>;
+
+struct GetRegistrationCallback {
+ registration_tx: Mutex<Option<RegistrationSender>>,
+}
+
+impl GetRegistrationCallback {
+ pub fn new_native_binder(
+ registration_tx: RegistrationSender,
+ ) -> Result<Strong<dyn IGetRegistrationCallback>> {
+ let result: Self =
+ GetRegistrationCallback { registration_tx: Mutex::new(Some(registration_tx)) };
+ Ok(BnGetRegistrationCallback::new_binder(result, BinderFeatures::default()))
+ }
+ fn on_success(&self, registration: &binder::Strong<dyn IRegistration>) -> Result<()> {
+ if let Some(tx) = self.registration_tx.lock().unwrap().take() {
+ tx.send(Ok(registration.clone())).unwrap();
+ }
+ Ok(())
+ }
+ fn on_cancel(&self) -> Result<()> {
+ if let Some(tx) = self.registration_tx.lock().unwrap().take() {
+ tx.send(
+ Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
+ .context(ks_err!("GetRegistrationCallback cancelled.")),
+ )
+ .unwrap();
+ }
+ Ok(())
+ }
+ fn on_error(&self, error: &str) -> Result<()> {
+ if let Some(tx) = self.registration_tx.lock().unwrap().take() {
+ tx.send(
+ Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+ .context(ks_err!("GetRegistrationCallback failed: {:?}", error)),
+ )
+ .unwrap();
+ }
+ Ok(())
+ }
+}
+
+impl Interface for GetRegistrationCallback {}
+
+impl IGetRegistrationCallback for GetRegistrationCallback {
+ fn onSuccess(&self, registration: &Strong<dyn IRegistration>) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetRegistrationCallback::onSuccess", 500);
+ map_or_log_err(self.on_success(registration), Ok)
+ }
+ fn onCancel(&self) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500);
+ map_or_log_err(self.on_cancel(), Ok)
+ }
+ fn onError(&self, error: &str) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
+ map_or_log_err(self.on_error(error), Ok)
+ }
+}
+
+/// Make a new connection to a IRegistration service.
+async fn get_rkpd_registration(
+ security_level: &SecurityLevel,
+) -> Result<binder::Strong<dyn IRegistration>> {
+ let remote_provisioning: Strong<dyn IRemoteProvisioning> =
+ map_binder_status_code(binder::get_interface("remote_provisioning"))
+ .context(ks_err!("Trying to connect to IRemoteProvisioning service."))?;
+
+ let rpc_name = get_remotely_provisioned_component_name(security_level)
+ .context(ks_err!("Trying to get IRPC name."))?;
+
+ let (tx, rx) = oneshot::channel();
+ let cb = GetRegistrationCallback::new_native_binder(tx)
+ .context(ks_err!("Trying to create a IGetRegistrationCallback."))?;
+
+ remote_provisioning
+ .getRegistration(&rpc_name, &cb)
+ .context(ks_err!("Trying to get registration."))?;
+
+ rx.await.unwrap()
+}
+
+type KeySender = oneshot::Sender<Result<RemotelyProvisionedKey>>;
+
+struct GetKeyCallback {
+ key_tx: Mutex<Option<KeySender>>,
+}
+
+impl GetKeyCallback {
+ pub fn new_native_binder(key_tx: KeySender) -> Result<Strong<dyn IGetKeyCallback>> {
+ let result: Self = GetKeyCallback { key_tx: Mutex::new(Some(key_tx)) };
+ Ok(BnGetKeyCallback::new_binder(result, BinderFeatures::default()))
+ }
+ fn on_success(&self, key: &RemotelyProvisionedKey) -> Result<()> {
+ if let Some(tx) = self.key_tx.lock().unwrap().take() {
+ tx.send(Ok(RemotelyProvisionedKey {
+ keyBlob: key.keyBlob.clone(),
+ encodedCertChain: key.encodedCertChain.clone(),
+ }))
+ .unwrap();
+ }
+ Ok(())
+ }
+ fn on_cancel(&self) -> Result<()> {
+ if let Some(tx) = self.key_tx.lock().unwrap().take() {
+ tx.send(
+ Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
+ .context(ks_err!("GetKeyCallback cancelled.")),
+ )
+ .unwrap();
+ }
+ Ok(())
+ }
+ fn on_error(&self, error: &str) -> Result<()> {
+ if let Some(tx) = self.key_tx.lock().unwrap().take() {
+ tx.send(
+ Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+ .context(ks_err!("GetKeyCallback failed: {:?}", error)),
+ )
+ .unwrap();
+ }
+ Ok(())
+ }
+}
+
+impl Interface for GetKeyCallback {}
+
+impl IGetKeyCallback for GetKeyCallback {
+ fn onSuccess(&self, key: &RemotelyProvisionedKey) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetKeyCallback::onSuccess", 500);
+ map_or_log_err(self.on_success(key), Ok)
+ }
+ fn onCancel(&self) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500);
+ map_or_log_err(self.on_cancel(), Ok)
+ }
+ fn onError(&self, error: &str) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetKeyCallback::onError", 500);
+ map_or_log_err(self.on_error(error), Ok)
+ }
+}
+
+async fn get_rkpd_attestation_key_async(
+ security_level: &SecurityLevel,
+ caller_uid: u32,
+) -> Result<RemotelyProvisionedKey> {
+ let registration = get_rkpd_registration(security_level)
+ .await
+ .context(ks_err!("Trying to get to IRegistration service."))?;
+
+ let (tx, rx) = oneshot::channel();
+ let cb = GetKeyCallback::new_native_binder(tx)
+ .context(ks_err!("Trying to create a IGetKeyCallback."))?;
+
+ registration
+ .getKey(caller_uid.try_into().unwrap(), &cb)
+ .context(ks_err!("Trying to get key."))?;
+
+ rx.await.unwrap()
+}
+
+async fn store_rkpd_attestation_key_async(
+ security_level: &SecurityLevel,
+ key_blob: &[u8],
+ upgraded_blob: &[u8],
+) -> Result<()> {
+ let registration = get_rkpd_registration(security_level)
+ .await
+ .context(ks_err!("Trying to get to IRegistration service."))?;
+
+ registration
+ .storeUpgradedKey(key_blob, upgraded_blob)
+ .context(ks_err!("Failed to store upgraded blob with RKPD."))?;
+ Ok(())
+}
+
+/// Get attestation key from RKPD.
+pub fn get_rkpd_attestation_key(
+ security_level: &SecurityLevel,
+ caller_uid: u32,
+) -> Result<RemotelyProvisionedKey> {
+ let _wp = wd::watch_millis("Calling get_rkpd_attestation_key()", 500);
+ block_on(get_rkpd_attestation_key_async(security_level, caller_uid))
+}
+
+/// Store attestation key in RKPD.
+pub fn store_rkpd_attestation_key(
+ security_level: &SecurityLevel,
+ key_blob: &[u8],
+ upgraded_blob: &[u8],
+) -> Result<()> {
+ let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
+ block_on(store_rkpd_attestation_key_async(security_level, key_blob, upgraded_blob))
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
+ use std::sync::Arc;
+
+ #[derive(Default)]
+ struct MockRegistrationValues {
+ _key: RemotelyProvisionedKey,
+ }
+
+ #[derive(Default)]
+ struct MockRegistration(Arc<Mutex<MockRegistrationValues>>);
+
+ impl MockRegistration {
+ pub fn new_native_binder() -> Strong<dyn IRegistration> {
+ let result: Self = Default::default();
+ BnRegistration::new_binder(result, BinderFeatures::default())
+ }
+ }
+
+ impl Interface for MockRegistration {}
+
+ impl IRegistration for MockRegistration {
+ fn getKey(&self, _: i32, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
+ todo!()
+ }
+
+ fn cancelGetKey(&self, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
+ todo!()
+ }
+
+ fn storeUpgradedKey(&self, _: &[u8], _: &[u8]) -> binder::Result<()> {
+ todo!()
+ }
+ }
+
+ fn get_mock_registration() -> Result<binder::Strong<dyn IRegistration>> {
+ let (tx, rx) = oneshot::channel();
+ let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+ let mock_registration = MockRegistration::new_native_binder();
+
+ assert!(cb.onSuccess(&mock_registration).is_ok());
+ block_on(rx).unwrap()
+ }
+
+ #[test]
+ fn test_get_registration_cb_success() {
+ let registration = get_mock_registration();
+ assert!(registration.is_ok());
+ }
+
+ #[test]
+ fn test_get_registration_cb_cancel() {
+ let (tx, rx) = oneshot::channel();
+ let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+ assert!(cb.onCancel().is_ok());
+
+ let result = block_on(rx).unwrap();
+ assert_eq!(
+ result.unwrap_err().downcast::<Error>().unwrap(),
+ Error::Km(ErrorCode::OPERATION_CANCELLED)
+ );
+ }
+
+ #[test]
+ fn test_get_registration_cb_error() {
+ let (tx, rx) = oneshot::channel();
+ let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+ assert!(cb.onError("error").is_ok());
+
+ let result = block_on(rx).unwrap();
+ assert_eq!(
+ result.unwrap_err().downcast::<Error>().unwrap(),
+ Error::Km(ErrorCode::UNKNOWN_ERROR)
+ );
+ }
+
+ #[test]
+ fn test_get_key_cb_success() {
+ let mock_key =
+ RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
+ let (tx, rx) = oneshot::channel();
+ let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+ assert!(cb.onSuccess(&mock_key).is_ok());
+
+ let key = block_on(rx).unwrap().unwrap();
+ assert_eq!(key, mock_key);
+ }
+
+ #[test]
+ fn test_get_key_cb_cancel() {
+ let (tx, rx) = oneshot::channel();
+ let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+ assert!(cb.onCancel().is_ok());
+
+ let result = block_on(rx).unwrap();
+ assert_eq!(
+ result.unwrap_err().downcast::<Error>().unwrap(),
+ Error::Km(ErrorCode::OPERATION_CANCELLED)
+ );
+ }
+
+ #[test]
+ fn test_get_key_cb_error() {
+ let (tx, rx) = oneshot::channel();
+ let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+ assert!(cb.onError("error").is_ok());
+
+ let result = block_on(rx).unwrap();
+ assert_eq!(
+ result.unwrap_err().downcast::<Error>().unwrap(),
+ Error::Km(ErrorCode::UNKNOWN_ERROR)
+ );
+ }
+
+ #[test]
+ #[ignore]
+ fn test_get_rkpd_attestation_key() {
+ let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, 0).unwrap();
+ assert!(!key.keyBlob.is_empty());
+ assert!(!key.encodedCertChain.is_empty());
+ }
+
+ #[test]
+ #[ignore]
+ fn test_get_rkpd_attestation_key_same_caller() {
+ let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+ let caller_uid = 0;
+
+ // Multiple calls should return the same key.
+ let first_key = get_rkpd_attestation_key(&sec_level, caller_uid).unwrap();
+ let second_key = get_rkpd_attestation_key(&sec_level, caller_uid).unwrap();
+
+ assert_eq!(first_key.keyBlob, second_key.keyBlob);
+ assert_eq!(first_key.encodedCertChain, second_key.encodedCertChain);
+ }
+
+ #[test]
+ #[ignore]
+ fn test_get_rkpd_attestation_key_different_caller() {
+ let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+
+ // Different callers should be getting different keys.
+ let first_key = get_rkpd_attestation_key(&sec_level, 1).unwrap();
+ let second_key = get_rkpd_attestation_key(&sec_level, 2).unwrap();
+
+ assert_ne!(first_key.keyBlob, second_key.keyBlob);
+ assert_ne!(first_key.encodedCertChain, second_key.encodedCertChain);
+ }
+
+ #[test]
+ #[ignore]
+ fn test_store_rkpd_attestation_key() {
+ let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+ let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, 0).unwrap();
+
+ assert!(store_rkpd_attestation_key(&sec_level, &key.keyBlob, &key.keyBlob).is_ok());
+ }
+}
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index ae49bc8..b928fb0 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -26,6 +26,7 @@
use crate::ks_err;
use crate::metrics_store::log_key_creation_event_stats;
use crate::remote_provisioning::RemProvState;
+use crate::rkpd_client::store_rkpd_attestation_key;
use crate::super_key::{KeyBlob, SuperKeyManager};
use crate::utils::{
check_device_attestation_permissions, check_key_permission,
@@ -148,7 +149,7 @@
SecurityLevel::SOFTWARE,
));
- let creation_date = DateTime::now().context("Trying to make creation time.")?;
+ let creation_date = DateTime::now().context(ks_err!("Trying to make creation time."))?;
let key = match key.domain {
Domain::BLOB => KeyDescriptor {
@@ -616,6 +617,30 @@
result.certificateChain.push(attestation_certs);
result
}),
+ Some(AttestationKeyInfo::RkpdProvisioned { attestation_key, attestation_certs }) => {
+ self.upgrade_rkpd_keyblob_if_required_with(&attestation_key.keyBlob, &[], |blob| {
+ map_km_error({
+ let _wp = self.watch_millis(
+ concat!(
+ "In KeystoreSecurityLevel::generate_key (RkpdProvisioned): ",
+ "calling generate_key.",
+ ),
+ 5000, // Generate can take a little longer.
+ );
+ let dynamic_attest_key = Some(AttestationKey {
+ keyBlob: blob.to_vec(),
+ attestKeyParams: vec![],
+ issuerSubjectName: attestation_key.issuerSubjectName.clone(),
+ });
+ self.keymint.generateKey(¶ms, dynamic_attest_key.as_ref())
+ })
+ })
+ .context("While generating Key with remote provisioned attestation key.")
+ .map(|(mut result, _)| {
+ result.certificateChain.push(attestation_certs);
+ result
+ })
+ }
None => map_km_error({
let _wp = self.watch_millis(
concat!(
@@ -677,7 +702,7 @@
KeyParameterValue::Algorithm(Algorithm::RSA)
| KeyParameterValue::Algorithm(Algorithm::EC) => Ok(KeyFormat::PKCS8),
v => Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
- .context(format!("Unknown Algorithm {:?}.", v)),
+ .context(ks_err!("Unknown Algorithm {:?}.", v)),
})
.context(ks_err!())?;
@@ -757,10 +782,10 @@
})
.context("Failed to load wrapping key.")?;
- let (wrapping_key_blob, wrapping_blob_metadata) = wrapping_key_entry
- .take_key_blob_info()
- .ok_or_else(error::Error::sys)
- .context("No km_blob after successfully loading key. This should never happen.")?;
+ let (wrapping_key_blob, wrapping_blob_metadata) =
+ wrapping_key_entry.take_key_blob_info().ok_or_else(error::Error::sys).context(
+ ks_err!("No km_blob after successfully loading key. This should never happen."),
+ )?;
let wrapping_key_blob = SUPER_KEY
.read()
@@ -888,6 +913,28 @@
Ok((v, upgraded_blob))
}
+ fn upgrade_rkpd_keyblob_if_required_with<T, F>(
+ &self,
+ key_blob: &[u8],
+ params: &[KeyParameter],
+ f: F,
+ ) -> Result<(T, Option<Vec<u8>>)>
+ where
+ F: Fn(&[u8]) -> Result<T, Error>,
+ {
+ crate::utils::upgrade_keyblob_if_required_with(
+ &*self.keymint,
+ key_blob,
+ params,
+ f,
+ |upgraded_blob| {
+ store_rkpd_attestation_key(&self.security_level, key_blob, upgraded_blob)
+ .context(ks_err!("Failed store_rkpd_attestation_key()."))
+ },
+ )
+ .context(ks_err!())
+ }
+
fn convert_storage_key_to_ephemeral(
&self,
storage_key: &KeyDescriptor,
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index a3e0fa5..f43ba5c 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -66,10 +66,7 @@
SecurityLevel::TRUSTED_ENVIRONMENT,
id_rotation_state.clone(),
)
- .context(concat!(
- "In KeystoreService::new_native_binder: ",
- "Trying to construct mandatory security level TEE."
- ))?;
+ .context(ks_err!("Trying to construct mandatory security level TEE."))?;
result.i_sec_level_by_uuid.insert(uuid, dev);
result.uuid_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, uuid);
@@ -86,9 +83,7 @@
.set_init(move || {
(create_thread_local_db(), uuid_by_sec_level, LEGACY_BLOB_LOADER.clone())
})
- .context(
- "In KeystoreService::new_native_binder: Trying to initialize the legacy migrator.",
- )?;
+ .context(ks_err!("Trying to initialize the legacy migrator."))?;
Ok(BnKeystoreService::new_binder(
result,
@@ -108,8 +103,7 @@
if let Some(dev) = self.i_sec_level_by_uuid.get(uuid) {
Ok(dev.clone())
} else {
- Err(error::Error::sys())
- .context("In get_i_sec_level_by_uuid: KeyMint instance for key not found.")
+ Err(error::Error::sys()).context(ks_err!("KeyMint instance for key not found."))
}
}
@@ -125,7 +119,7 @@
Ok(dev.clone())
} else {
Err(error::Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
- .context("In get_security_level: No such security level.")
+ .context(ks_err!("No such security level."))
}
}
@@ -147,12 +141,12 @@
)
})
})
- .context("In get_key_entry, while trying to load key info.")?;
+ .context(ks_err!("while trying to load key info."))?;
let i_sec_level = if !key_entry.pure_cert() {
Some(
self.get_i_sec_level_by_uuid(key_entry.km_uuid())
- .context("In get_key_entry: Trying to get security level proxy.")?,
+ .context(ks_err!("Trying to get security level proxy."))?,
)
} else {
None
@@ -174,7 +168,7 @@
.creation_date()
.map(|d| d.to_millis_epoch())
.ok_or(Error::Rc(ResponseCode::VALUE_CORRUPTED))
- .context("In get_key_entry: Trying to get creation date.")?,
+ .context(ks_err!("Trying to get creation date."))?,
authorizations: key_parameters_to_authorizations(key_entry.into_key_parameters()),
},
})
@@ -197,10 +191,7 @@
KeyType::Client,
KeyEntryLoadBits::NONE,
caller_uid,
- |k, av| {
- check_key_permission(KeyPerm::Update, k, &av)
- .context("In update_subcomponent.")
- },
+ |k, av| check_key_permission(KeyPerm::Update, k, &av).context(ks_err!()),
)
}) {
Err(e) => match e.root_cause().downcast_ref::<Error>() {
@@ -209,7 +200,7 @@
},
Ok(v) => Ok(Some(v)),
}
- .context("Failed to load key entry.")?;
+ .context(ks_err!("Failed to load key entry."))?;
let mut db = db.borrow_mut();
if let Some((key_id_guard, _key_entry)) = entry {
@@ -256,7 +247,7 @@
.context("Failed to insert new certificate.")?;
Ok(())
})
- .context("In update_subcomponent.")
+ .context(ks_err!())
}
fn list_entries(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index dd22d8b..f000213 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -25,6 +25,7 @@
error::Error,
error::ResponseCode,
key_parameter::{KeyParameter, KeyParameterValue},
+ ks_err,
legacy_blob::LegacyBlobLoader,
legacy_importer::LegacyImporter,
raw_device::KeyMintDevice,
@@ -156,19 +157,17 @@
impl AesGcm for SuperKey {
fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm {
- aes_gcm_decrypt(data, iv, tag, &self.key)
- .context("In SuperKey::decrypt: Decryption failed.")
+ aes_gcm_decrypt(data, iv, tag, &self.key).context(ks_err!("Decryption failed."))
} else {
- Err(Error::sys()).context("In SuperKey::decrypt: Key is not an AES key.")
+ Err(Error::sys()).context(ks_err!("Key is not an AES key."))
}
}
fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm {
- aes_gcm_encrypt(plaintext, &self.key)
- .context("In SuperKey::encrypt: Encryption failed.")
+ aes_gcm_encrypt(plaintext, &self.key).context(ks_err!("Encryption failed."))
} else {
- Err(Error::sys()).context("In SuperKey::encrypt: Key is not an AES key.")
+ Err(Error::sys()).context(ks_err!("Key is not an AES key."))
}
}
}
@@ -203,7 +202,7 @@
.as_ref()
.map(|(key_blob, _)| KeyBlob::Ref(key_blob))
.ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
- .context("In LockedKey::decrypt: Missing key blob info.")?;
+ .context(ks_err!("Missing key blob info."))?;
let key_params = vec![
KeyParameterValue::Algorithm(Algorithm::AES),
KeyParameterValue::KeySize(256),
@@ -270,10 +269,7 @@
self.key_index.insert(id, Arc::downgrade(super_key));
Ok(())
} else {
- Err(Error::sys()).context(format!(
- "In add_key_to_key_index: cannot add key with ID {:?}",
- super_key.id
- ))
+ Err(Error::sys()).context(ks_err!("Cannot add key with ID {:?}", super_key.id))
}
}
}
@@ -290,8 +286,8 @@
log::info!("In set_up_boot_level_cache: called for a second time");
return Ok(());
}
- let level_zero_key = get_level_zero_key(db)
- .context("In set_up_boot_level_cache: get_level_zero_key failed")?;
+ let level_zero_key =
+ get_level_zero_key(db).context(ks_err!("get_level_zero_key failed"))?;
skm_guard.data.boot_level_key_cache =
Some(Mutex::new(BootLevelKeyCache::new(level_zero_key)));
log::info!("Starting boot level watcher.");
@@ -307,11 +303,11 @@
/// Blocks waiting for system property changes, so must be run in its own thread.
fn watch_boot_level(skm: Arc<RwLock<Self>>) -> Result<()> {
let mut w = PropertyWatcher::new("keystore.boot_level")
- .context("In watch_boot_level: PropertyWatcher::new failed")?;
+ .context(ks_err!("PropertyWatcher::new failed"))?;
loop {
let level = w
.read(|_n, v| v.parse::<usize>().map_err(std::convert::Into::into))
- .context("In watch_boot_level: read of property failed")?;
+ .context(ks_err!("read of property failed"))?;
// This scope limits the skm_guard life, so we don't hold the skm_guard while
// waiting.
@@ -322,14 +318,14 @@
.boot_level_key_cache
.as_mut()
.ok_or_else(Error::sys)
- .context("In watch_boot_level: Boot level cache not initialized")?
+ .context(ks_err!("Boot level cache not initialized"))?
.get_mut()
.unwrap();
if level < MAX_MAX_BOOT_LEVEL {
log::info!("Read keystore.boot_level value {}", level);
boot_level_key_cache
.advance_boot_level(level)
- .context("In watch_boot_level: advance_boot_level failed")?;
+ .context(ks_err!("advance_boot_level failed"))?;
} else {
log::info!(
"keystore.boot_level {} hits maximum {}, finishing.",
@@ -340,7 +336,7 @@
break;
}
}
- w.wait().context("In watch_boot_level: property wait failed")?;
+ w.wait().context(ks_err!("property wait failed"))?;
}
Ok(())
}
@@ -363,7 +359,7 @@
) -> Result<()> {
self.data
.add_key_to_key_index(&super_key)
- .context("In install_per_boot_key_for_user: add_key_to_key_index failed")?;
+ .context(ks_err!("add_key_to_key_index failed"))?;
self.data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Ok(())
}
@@ -379,7 +375,7 @@
.as_ref()
.map(|b| b.lock().unwrap().aes_key(*level as usize))
.transpose()
- .context("In lookup_key: aes_key failed")?
+ .context(ks_err!("aes_key failed"))?
.flatten()
.map(|key| {
Arc::new(SuperKey {
@@ -425,12 +421,12 @@
// For backward compatibility we need to check if there is a super key present.
let super_key = legacy_blob_loader
.load_super_key(user, pw)
- .context("In create_new_key: Failed to load legacy key blob.")?;
+ .context(ks_err!("Failed to load legacy key blob."))?;
let super_key = match super_key {
None => {
// No legacy file was found. So we generate a new key.
generate_aes256_key()
- .context("In create_new_key: Failed to generate AES 256 key.")?
+ .context(ks_err!("Failed to generate AES 256 key."))?
}
Some(key) => key,
};
@@ -442,10 +438,10 @@
Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
},
)
- .context("In unlock_user_key: Failed to get key id.")?;
+ .context(ks_err!("Failed to get key id."))?;
self.populate_cache_from_super_key_blob(user, USER_SUPER_KEY.algorithm, entry, pw)
- .context("In unlock_user_key.")?;
+ .context(ks_err!())?;
Ok(())
}
@@ -459,12 +455,12 @@
Ok(if let Some(key_id) = SuperKeyIdentifier::from_metadata(metadata) {
let super_key = self
.lookup_key(&key_id)
- .context("In unwrap_key: lookup_key failed")?
+ .context(ks_err!("lookup_key failed"))?
.ok_or(Error::Rc(ResponseCode::LOCKED))
- .context("In unwrap_key: Required super decryption key is not in memory.")?;
+ .context(ks_err!("Required super decryption key is not in memory."))?;
KeyBlob::Sensitive {
key: Self::unwrap_key_with_key(blob, metadata, &super_key)
- .context("In unwrap_key: unwrap_key_with_key failed")?,
+ .context(ks_err!("unwrap_key_with_key failed"))?,
reencrypt_with: super_key.reencrypt_with.as_ref().unwrap_or(&super_key).clone(),
force_reencrypt: super_key.reencrypt_with.is_some(),
}
@@ -477,14 +473,11 @@
fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec> {
match key.algorithm {
SuperEncryptionAlgorithm::Aes256Gcm => match (metadata.iv(), metadata.aead_tag()) {
- (Some(iv), Some(tag)) => key
- .decrypt(blob, iv, tag)
- .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
- (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
- concat!(
- "In unwrap_key_with_key: Key has incomplete metadata.",
- "Present: iv: {}, aead_tag: {}."
- ),
+ (Some(iv), Some(tag)) => {
+ key.decrypt(blob, iv, tag).context(ks_err!("Failed to decrypt the key blob."))
+ }
+ (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
+ "Key has incomplete metadata. Present: iv: {}, aead_tag: {}.",
iv.is_some(),
tag.is_some(),
)),
@@ -494,14 +487,12 @@
(Some(public_key), Some(salt), Some(iv), Some(aead_tag)) => {
ECDHPrivateKey::from_private_key(&key.key)
.and_then(|k| k.decrypt_message(public_key, salt, iv, blob, aead_tag))
- .context(
- "In unwrap_key_with_key: Failed to decrypt the key blob with ECDH.",
- )
+ .context(ks_err!("Failed to decrypt the key blob with ECDH."))
}
(public_key, salt, iv, aead_tag) => {
- Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
+ Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
concat!(
- "In unwrap_key_with_key: Key has incomplete metadata.",
+ "Key has incomplete metadata. ",
"Present: public_key: {}, salt: {}, iv: {}, aead_tag: {}."
),
public_key.is_some(),
@@ -526,14 +517,12 @@
) -> Result<bool> {
let key_in_db = db
.key_exists(Domain::APP, user_id as u64 as i64, USER_SUPER_KEY.alias, KeyType::Super)
- .context("In super_key_exists_in_db_for_user.")?;
+ .context(ks_err!())?;
if key_in_db {
Ok(key_in_db)
} else {
- legacy_importer
- .has_super_key(user_id)
- .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
+ legacy_importer.has_super_key(user_id).context(ks_err!("Trying to query legacy db."))
}
}
@@ -550,13 +539,13 @@
let alias = &USER_SUPER_KEY;
let result = legacy_importer
.with_try_import_super_key(user_id, pw, || db.load_super_key(alias, user_id))
- .context("In check_and_unlock_super_key. Failed to load super key")?;
+ .context(ks_err!("Failed to load super key"))?;
match result {
Some((_, entry)) => {
let super_key = self
.populate_cache_from_super_key_blob(user_id, alias.algorithm, entry, pw)
- .context("In check_and_unlock_super_key.")?;
+ .context(ks_err!())?;
Ok(UserState::LskfUnlocked(super_key))
}
None => Ok(UserState::Uninitialized),
@@ -578,17 +567,17 @@
) -> Result<UserState> {
let super_key_exists_in_db = self
.super_key_exists_in_db_for_user(db, legacy_importer, user_id)
- .context("In check_and_initialize_super_key. Failed to check if super key exists.")?;
+ .context(ks_err!("Failed to check if super key exists."))?;
if super_key_exists_in_db {
Ok(UserState::LskfLocked)
} else if let Some(pw) = pw {
// Generate a new super key.
- let super_key = generate_aes256_key()
- .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
+ let super_key =
+ generate_aes256_key().context(ks_err!("Failed to generate AES 256 key."))?;
// Derive an AES256 key from the password and re-encrypt the super key
// before we insert it in the database.
- let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
- .context("In check_and_initialize_super_key.")?;
+ let (encrypted_super_key, blob_metadata) =
+ Self::encrypt_with_password(&super_key, pw).context(ks_err!())?;
let key_entry = db
.store_super_key(
@@ -598,7 +587,7 @@
&blob_metadata,
&KeyMetaData::new(),
)
- .context("In check_and_initialize_super_key. Failed to store super key.")?;
+ .context(ks_err!("Failed to store super key."))?;
let super_key = self
.populate_cache_from_super_key_blob(
@@ -607,7 +596,7 @@
key_entry,
pw,
)
- .context("In check_and_initialize_super_key.")?;
+ .context(ks_err!())?;
Ok(UserState::LskfUnlocked(super_key))
} else {
Ok(UserState::Uninitialized)
@@ -623,9 +612,7 @@
pw: &Password,
) -> Result<Arc<SuperKey>> {
let super_key = Self::extract_super_key_from_key_entry(algorithm, entry, pw, None)
- .context(
- "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
- )?;
+ .context(ks_err!("Failed to extract super key from key entry"))?;
self.install_per_boot_key_for_user(user_id, super_key.clone())?;
Ok(super_key)
}
@@ -646,20 +633,19 @@
) {
(Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
// Note that password encryption is AES no matter the value of algorithm.
- let key = pw.derive_key(salt, AES_256_KEY_LENGTH).context(
- "In extract_super_key_from_key_entry: Failed to generate key from password.",
- )?;
+ let key = pw
+ .derive_key(salt, AES_256_KEY_LENGTH)
+ .context(ks_err!("Failed to generate key from password."))?;
- aes_gcm_decrypt(blob, iv, tag, &key).context(
- "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
- )?
+ aes_gcm_decrypt(blob, iv, tag, &key)
+ .context(ks_err!("Failed to decrypt key blob."))?
}
(enc_by, salt, iv, tag) => {
- return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
+ return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
concat!(
- "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
- "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}."
- ),
+ "Super key has incomplete metadata.",
+ "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}."
+ ),
enc_by,
salt.is_some(),
iv.is_some(),
@@ -674,8 +660,7 @@
reencrypt_with,
}))
} else {
- Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
- .context("In extract_super_key_from_key_entry: No key blob info.")
+ Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!("No key blob info."))
}
}
@@ -687,12 +672,12 @@
let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
let derived_key = pw
.derive_key(&salt, AES_256_KEY_LENGTH)
- .context("In encrypt_with_password: Failed to derive password.")?;
+ .context(ks_err!("Failed to derive password."))?;
let mut metadata = BlobMetaData::new();
metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
metadata.add(BlobMetaEntry::Salt(salt));
let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
- .context("In encrypt_with_password: Failed to encrypt new super key.")?;
+ .context(ks_err!("Failed to encrypt new super key."))?;
metadata.add(BlobMetaEntry::Iv(iv));
metadata.add(BlobMetaEntry::AeadTag(tag));
Ok((encrypted_key, metadata))
@@ -711,17 +696,17 @@
) -> Result<(Vec<u8>, BlobMetaData)> {
match self
.get_user_state(db, legacy_importer, user_id)
- .context("In super_encrypt. Failed to get user state.")?
+ .context(ks_err!("Failed to get user state."))?
{
UserState::LskfUnlocked(super_key) => {
Self::encrypt_with_aes_super_key(key_blob, &super_key)
- .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
+ .context(ks_err!("Failed to encrypt the key."))
}
UserState::LskfLocked => {
- Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
+ Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked."))
}
UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
- .context("In super_encrypt. LSKF is not setup for the user."),
+ .context(ks_err!("LSKF is not setup for the user.")),
}
}
@@ -733,12 +718,11 @@
super_key: &SuperKey,
) -> Result<(Vec<u8>, BlobMetaData)> {
if super_key.algorithm != SuperEncryptionAlgorithm::Aes256Gcm {
- return Err(Error::sys())
- .context("In encrypt_with_aes_super_key: unexpected algorithm");
+ return Err(Error::sys()).context(ks_err!("unexpected algorithm"));
}
let mut metadata = BlobMetaData::new();
let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
- .context("In encrypt_with_aes_super_key: Failed to encrypt new super key.")?;
+ .context(ks_err!("Failed to encrypt new super key."))?;
metadata.add(BlobMetaEntry::Iv(iv));
metadata.add(BlobMetaEntry::AeadTag(tag));
super_key.id.add_to_metadata(&mut metadata);
@@ -762,37 +746,29 @@
SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
SuperEncryptionType::LskfBound => self
.super_encrypt_on_key_init(db, legacy_importer, user_id, key_blob)
- .context(concat!(
- "In handle_super_encryption_on_key_init. ",
- "Failed to super encrypt with LskfBound key."
- )),
+ .context(ks_err!("Failed to super encrypt with LskfBound key.")),
SuperEncryptionType::ScreenLockBound => {
let entry =
self.data.user_keys.get(&user_id).and_then(|e| e.screen_lock_bound.as_ref());
if let Some(super_key) = entry {
- Self::encrypt_with_aes_super_key(key_blob, super_key).context(concat!(
- "In handle_super_encryption_on_key_init. ",
- "Failed to encrypt with ScreenLockBound key."
- ))
+ Self::encrypt_with_aes_super_key(key_blob, super_key)
+ .context(ks_err!("Failed to encrypt with ScreenLockBound key."))
} else {
// Symmetric key is not available, use public key encryption
- let loaded =
- db.load_super_key(&USER_SCREEN_LOCK_BOUND_P521_KEY, user_id).context(
- "In handle_super_encryption_on_key_init: load_super_key failed.",
- )?;
- let (key_id_guard, key_entry) = loaded.ok_or_else(Error::sys).context(
- "In handle_super_encryption_on_key_init: User ECDH key missing.",
- )?;
- let public_key =
- key_entry.metadata().sec1_public_key().ok_or_else(Error::sys).context(
- "In handle_super_encryption_on_key_init: sec1_public_key missing.",
- )?;
+ let loaded = db
+ .load_super_key(&USER_SCREEN_LOCK_BOUND_P521_KEY, user_id)
+ .context(ks_err!("load_super_key failed."))?;
+ let (key_id_guard, key_entry) =
+ loaded.ok_or_else(Error::sys).context(ks_err!("User ECDH key missing."))?;
+ let public_key = key_entry
+ .metadata()
+ .sec1_public_key()
+ .ok_or_else(Error::sys)
+ .context(ks_err!("sec1_public_key missing."))?;
let mut metadata = BlobMetaData::new();
let (ephem_key, salt, iv, encrypted_key, aead_tag) =
- ECDHPrivateKey::encrypt_message(public_key, key_blob).context(concat!(
- "In handle_super_encryption_on_key_init: ",
- "ECDHPrivateKey::encrypt_message failed."
- ))?;
+ ECDHPrivateKey::encrypt_message(public_key, key_blob)
+ .context(ks_err!("ECDHPrivateKey::encrypt_message failed."))?;
metadata.add(BlobMetaEntry::PublicKey(ephem_key));
metadata.add(BlobMetaEntry::Salt(salt));
metadata.add(BlobMetaEntry::Iv(iv));
@@ -806,13 +782,11 @@
let key_id = SuperKeyIdentifier::BootLevel(level);
let super_key = self
.lookup_key(&key_id)
- .context("In handle_super_encryption_on_key_init: lookup_key failed")?
+ .context(ks_err!("lookup_key failed"))?
.ok_or(Error::Rc(ResponseCode::LOCKED))
- .context("In handle_super_encryption_on_key_init: Boot stage key absent")?;
- Self::encrypt_with_aes_super_key(key_blob, &super_key).context(concat!(
- "In handle_super_encryption_on_key_init: ",
- "Failed to encrypt with BootLevel key."
- ))
+ .context(ks_err!("Boot stage key absent"))?;
+ Self::encrypt_with_aes_super_key(key_blob, &super_key)
+ .context(ks_err!("Failed to encrypt with BootLevel key."))
}
}
}
@@ -828,7 +802,7 @@
KeyBlob::Sensitive { reencrypt_with: super_key, .. } => {
let (key, metadata) =
Self::encrypt_with_aes_super_key(key_after_upgrade, super_key)
- .context("In reencrypt_if_required: Failed to re-super-encrypt key.")?;
+ .context(ks_err!("Failed to re-super-encrypt key."))?;
Ok((KeyBlob::NonSensitive(key), Some(metadata)))
}
_ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
@@ -857,28 +831,22 @@
} else {
let (super_key, public_key) = match key_type.algorithm {
SuperEncryptionAlgorithm::Aes256Gcm => (
- generate_aes256_key()
- .context("In get_or_create_super_key: Failed to generate AES 256 key.")?,
+ generate_aes256_key().context(ks_err!("Failed to generate AES 256 key."))?,
None,
),
SuperEncryptionAlgorithm::EcdhP521 => {
let key = ECDHPrivateKey::generate()
- .context("In get_or_create_super_key: Failed to generate ECDH key")?;
+ .context(ks_err!("Failed to generate ECDH key"))?;
(
- key.private_key()
- .context("In get_or_create_super_key: private_key failed")?,
- Some(
- key.public_key()
- .context("In get_or_create_super_key: public_key failed")?,
- ),
+ key.private_key().context(ks_err!("private_key failed"))?,
+ Some(key.public_key().context(ks_err!("public_key failed"))?),
)
}
};
// Derive an AES256 key from the password and re-encrypt the super key
// before we insert it in the database.
let (encrypted_super_key, blob_metadata) =
- Self::encrypt_with_password(&super_key, password)
- .context("In get_or_create_super_key.")?;
+ Self::encrypt_with_password(&super_key, password).context(ks_err!())?;
let mut key_metadata = KeyMetaData::new();
if let Some(pk) = public_key {
key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk));
@@ -891,7 +859,7 @@
&blob_metadata,
&key_metadata,
)
- .context("In get_or_create_super_key. Failed to store super key.")?;
+ .context(ks_err!("Failed to store super key."))?;
Ok(Arc::new(SuperKey {
algorithm: key_type.algorithm,
key: super_key,
@@ -926,7 +894,7 @@
screen_lock_bound
} else {
self.get_or_create_super_key(db, user_id, &USER_SCREEN_LOCK_BOUND_KEY, password, None)
- .context("In unlock_screen_lock_bound_key: Trying to get or create symmetric key.")?
+ .context(ks_err!("Trying to get or create symmetric key."))?
};
let ecdh = if let Some(screen_lock_bound_private) = screen_lock_bound_private {
@@ -941,7 +909,7 @@
password,
Some(aes.clone()),
)
- .context("In unlock_screen_lock_bound_key: Trying to get or create asymmetric key.")?
+ .context(ks_err!("Trying to get or create asymmetric key."))?
};
self.data.add_key_to_key_index(&aes)?;
@@ -974,7 +942,7 @@
let encrypting_key = generate_aes256_key()?;
let km_dev: KeyMintDevice =
KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
- .context("In lock_screen_lock_bound_key: KeyMintDevice::get failed")?;
+ .context(ks_err!("KeyMintDevice::get failed"))?;
let mut key_params = vec![
KeyParameterValue::Algorithm(Algorithm::AES),
KeyParameterValue::KeySize(256),
@@ -1046,9 +1014,9 @@
AID_KEYSTORE,
|_, _| Ok(()),
)
- .context("In try_unlock_user_with_biometric: load_key_entry failed")?;
+ .context(ks_err!("load_key_entry failed"))?;
let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
- .context("In try_unlock_user_with_biometric: KeyMintDevice::get failed")?;
+ .context(ks_err!("KeyMintDevice::get failed"))?;
for sid in &biometric.sids {
if let Some((auth_token_entry, _)) = db.find_auth_token_entry(|entry| {
entry.auth_token().userId == *sid || entry.auth_token().authenticatorId == *sid
@@ -1078,14 +1046,11 @@
entry.screen_lock_bound_private = Some(slbp.clone());
self.data.add_key_to_key_index(&slb)?;
self.data.add_key_to_key_index(&slbp)?;
- log::info!(concat!(
- "In try_unlock_user_with_biometric: ",
- "Successfully unlocked with biometric"
- ));
+ log::info!("Successfully unlocked with biometric");
return Ok(());
}
Err(e) => {
- log::warn!("In try_unlock_user_with_biometric: attempt failed: {:?}", e)
+ log::warn!("attempt failed: {:?}", e)
}
}
}
@@ -1110,7 +1075,7 @@
// If so, return locked user state.
if self
.super_key_exists_in_db_for_user(db, legacy_importer, user_id)
- .context("In get_user_state.")?
+ .context(ks_err!())?
{
Ok(UserState::LskfLocked)
} else {
@@ -1141,9 +1106,8 @@
Some(_) if password.is_none() => {
// Transitioning to swiping, delete only the super key in database and cache,
// and super-encrypted keys in database (and in KM).
- self.reset_user(db, legacy_importer, user_id, true).context(
- "In reset_or_init_user_and_get_user_state: Trying to delete keys from the db.",
- )?;
+ self.reset_user(db, legacy_importer, user_id, true)
+ .context(ks_err!("Trying to delete keys from the db."))?;
// Lskf is now removed in Keystore.
Ok(UserState::Uninitialized)
}
@@ -1174,7 +1138,7 @@
) -> Result<UserState> {
match self.get_per_boot_key_by_user_id_internal(user_id) {
Some(super_key) => {
- log::info!("In unlock_and_get_user_state. Trying to unlock when already unlocked.");
+ log::info!("Trying to unlock when already unlocked.");
Ok(UserState::LskfUnlocked(super_key))
}
None => {
@@ -1183,7 +1147,7 @@
// Otherwise, try to unlock the super key and if successful,
// return LskfUnlocked.
self.check_and_unlock_super_key(db, legacy_importer, user_id, password)
- .context("In unlock_and_get_user_state. Failed to unlock super key.")
+ .context(ks_err!("Failed to unlock super key."))
}
}
}
@@ -1201,9 +1165,9 @@
// Mark keys created on behalf of the user as unreferenced.
legacy_importer
.bulk_delete_user(user_id, keep_non_super_encrypted_keys)
- .context("In reset_user: Trying to delete legacy keys.")?;
+ .context(ks_err!("Trying to delete legacy keys."))?;
db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
- .context("In reset user. Error in unbinding keys.")?;
+ .context(ks_err!("Error in unbinding keys."))?;
// Delete super key in cache, if exists.
self.forget_all_keys_for_user(user_id);
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 9db2eb9..75d98e2 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -17,6 +17,7 @@
use crate::error::{map_binder_status, map_km_error, Error, ErrorCode};
use crate::key_parameter::KeyParameter;
+use crate::ks_err;
use crate::permission;
use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
use crate::{
@@ -51,9 +52,9 @@
pub fn check_keystore_permission(perm: KeystorePerm) -> anyhow::Result<()> {
ThreadState::with_calling_sid(|calling_sid| {
permission::check_keystore_permission(
- calling_sid.ok_or_else(Error::sys).context(
- "In check_keystore_permission: Cannot check permission without calling_sid.",
- )?,
+ calling_sid
+ .ok_or_else(Error::sys)
+ .context(ks_err!("Cannot check permission without calling_sid."))?,
perm,
)
})
@@ -65,9 +66,9 @@
pub fn check_grant_permission(access_vec: KeyPermSet, key: &KeyDescriptor) -> anyhow::Result<()> {
ThreadState::with_calling_sid(|calling_sid| {
permission::check_grant_permission(
- calling_sid.ok_or_else(Error::sys).context(
- "In check_grant_permission: Cannot check permission without calling_sid.",
- )?,
+ calling_sid
+ .ok_or_else(Error::sys)
+ .context(ks_err!("Cannot check permission without calling_sid."))?,
access_vec,
key,
)
@@ -87,7 +88,7 @@
ThreadState::get_calling_uid(),
calling_sid
.ok_or_else(Error::sys)
- .context("In check_key_permission: Cannot check permission without calling_sid.")?,
+ .context(ks_err!("Cannot check permission without calling_sid."))?,
perm,
key,
access_vector,
@@ -103,6 +104,7 @@
| Tag::ATTESTATION_ID_MEID
| Tag::ATTESTATION_ID_SERIAL
| Tag::DEVICE_UNIQUE_ATTESTATION
+ | Tag::ATTESTATION_ID_SECOND_IMEI
)
}
@@ -135,14 +137,12 @@
ThreadState::get_calling_uid() as i32,
)
};
- let has_permissions = map_binder_status(binder_result)
- .context("In check_device_attestation_permissions: checkPermission failed")?;
+ let has_permissions =
+ map_binder_status(binder_result).context(ks_err!("checkPermission failed"))?;
match has_permissions {
true => Ok(()),
- false => Err(Error::Km(ErrorCode::CANNOT_ATTEST_IDS)).context(concat!(
- "In check_device_attestation_permissions: ",
- "caller does not have the permission to attest device IDs"
- )),
+ false => Err(Error::Km(ErrorCode::CANNOT_ATTEST_IDS))
+ .context(ks_err!("caller does not have the permission to attest device IDs")),
}
}
@@ -189,18 +189,15 @@
);
map_km_error(km_dev.upgradeKey(key_blob, upgrade_params))
}
- .context("In utils::upgrade_keyblob_if_required_with: Upgrade failed.")?;
+ .context(ks_err!("Upgrade failed."))?;
- new_blob_handler(&upgraded_blob)
- .context("In utils::upgrade_keyblob_if_required_with: calling new_blob_handler.")?;
+ new_blob_handler(&upgraded_blob).context(ks_err!("calling new_blob_handler."))?;
km_op(&upgraded_blob)
.map(|v| (v, Some(upgraded_blob)))
- .context("In utils::upgrade_keyblob_if_required_with: Calling km_op after upgrade.")
+ .context(ks_err!("Calling km_op after upgrade."))
}
- r => r
- .map(|v| (v, None))
- .context("In utils::upgrade_keyblob_if_required_with: Calling km_op."),
+ r => r.map(|v| (v, None)).context(ks_err!("Calling km_op.")),
}
}
@@ -270,12 +267,12 @@
result.append(
&mut LEGACY_IMPORTER
.list_uid(domain, namespace)
- .context("In list_key_entries: Trying to list legacy keys.")?,
+ .context(ks_err!("Trying to list legacy keys."))?,
);
result.append(
&mut db
.list(domain, namespace, KeyType::Client)
- .context("In list_key_entries: Trying to list keystore database.")?,
+ .context(ks_err!("Trying to list keystore database."))?,
);
result.sort_unstable();
result.dedup();
@@ -333,12 +330,11 @@
impl<T: AesGcmKey> AesGcm for T {
fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
- aes_gcm_decrypt(data, iv, tag, self.key())
- .context("In AesGcm<T>::decrypt: Decryption failed")
+ aes_gcm_decrypt(data, iv, tag, self.key()).context(ks_err!("Decryption failed"))
}
fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
- aes_gcm_encrypt(plaintext, self.key()).context("In AesGcm<T>::encrypt: Encryption failed.")
+ aes_gcm_encrypt(plaintext, self.key()).context(ks_err!("Encryption failed."))
}
}
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index d5c7299..0b631da 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -29,14 +29,12 @@
#include "android-base/errors.h"
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <asm/byteorder.h>
#include <libfsverity.h>
#include <linux/fsverity.h>
-#include "CertUtils.h"
-#include "SigningKey.h"
-
#define FS_VERITY_MAX_DIGEST_SIZE 64
using android::base::ErrnoError;
@@ -59,23 +57,6 @@
return ss.str();
}
-static std::vector<uint8_t> fromHex(std::string_view hex) {
- if (hex.size() % 2 != 0) {
- return {};
- }
- std::vector<uint8_t> result;
- result.reserve(hex.size() / 2);
- for (size_t i = 0; i < hex.size(); i += 2) {
- uint8_t byte;
- auto conversion_result = std::from_chars(&hex[i], &hex[i + 2], byte, 16);
- if (conversion_result.ptr != &hex[i + 2] || conversion_result.ec != std::errc()) {
- return {};
- }
- result.push_back(byte);
- }
- return result;
-}
-
static int read_callback(void* file, void* buf, size_t count) {
int* fd = (int*)file;
if (TEMP_FAILURE_RETRY(read(*fd, buf, count)) < 0) return errno ? -errno : -EIO;
@@ -163,28 +144,9 @@
} // namespace
-static Result<std::vector<uint8_t>> signDigest(const SigningKey& key,
- const std::vector<uint8_t>& digest) {
- auto d = makeUniqueWithTrailingData<fsverity_formatted_digest>(digest.size());
-
- memcpy(d->magic, "FSVerity", 8);
- d->digest_algorithm = __cpu_to_le16(FS_VERITY_HASH_ALG_SHA256);
- d->digest_size = __cpu_to_le16(digest.size());
- memcpy(d->digest, digest.data(), digest.size());
-
- auto signed_digest = key.sign(std::string((char*)d.get(), sizeof(*d) + digest.size()));
- if (!signed_digest.ok()) {
- return signed_digest.error();
- }
-
- return std::vector<uint8_t>(signed_digest->begin(), signed_digest->end());
-}
-
-static Result<void> enableFsVerity(int fd, std::span<uint8_t> pkcs7) {
+static Result<void> enableFsVerity(int fd) {
struct fsverity_enable_arg arg = {.version = 1};
- arg.sig_ptr = reinterpret_cast<uint64_t>(pkcs7.data());
- arg.sig_size = pkcs7.size();
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
arg.block_size = 4096;
@@ -197,29 +159,13 @@
return {};
}
-Result<std::string> enableFsVerity(int fd, const SigningKey& key) {
- auto digest = createDigest(fd);
- if (!digest.ok()) {
- return Error() << digest.error();
+Result<void> enableFsVerity(const std::string& path) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (!fd.ok()) {
+ return Error() << "Can't open " << path;
}
- auto signed_digest = signDigest(key, digest.value());
- if (!signed_digest.ok()) {
- return signed_digest.error();
- }
-
- auto pkcs7_data = createPkcs7(signed_digest.value(), kRootSubject);
- if (!pkcs7_data.ok()) {
- return pkcs7_data.error();
- }
-
- auto enabled = enableFsVerity(fd, pkcs7_data.value());
- if (!enabled.ok()) {
- return Error() << enabled.error();
- }
-
- // Return the root hash as a hex string
- return toHex(digest.value());
+ return enableFsVerity(fd.get());
}
static Result<bool> isFileInVerity(int fd) {
@@ -230,8 +176,7 @@
return (flags & FS_VERITY_FL) != 0;
}
-Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path,
- const SigningKey& key) {
+Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path) {
std::map<std::string, std::string> digests;
std::error_code ec;
@@ -245,7 +190,7 @@
auto enabled = OR_RETURN(isFileInVerity(fd));
if (!enabled) {
LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
- OR_RETURN(enableFsVerity(fd, key));
+ OR_RETURN(enableFsVerity(fd));
} else {
LOG(INFO) << it->path() << " was already in fs-verity.";
}
@@ -260,23 +205,6 @@
return digests;
}
-Result<void> enableFsVerity(const std::string& path, const std::string& signature_path) {
- unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
- if (!fd.ok()) {
- return Error() << "Can't open " << path;
- }
-
- std::string signature;
- android::base::ReadFileToString(signature_path, &signature);
- std::vector<uint8_t> span = std::vector<uint8_t>(signature.begin(), signature.end());
-
- const auto& enable = enableFsVerity(fd.get(), span);
- if (!enable.ok()) {
- return enable.error();
- }
- return {};
-}
-
Result<std::map<std::string, std::string>> verifyAllFilesInVerity(const std::string& path) {
std::map<std::string, std::string> digests;
std::error_code ec;
@@ -306,8 +234,7 @@
}
Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
- const std::map<std::string, std::string>& digests,
- const SigningKey& signing_key) {
+ const std::map<std::string, std::string>& digests) {
std::error_code ec;
size_t verified_count = 0;
auto it = std::filesystem::recursive_directory_iterator(directory_path, ec);
@@ -325,41 +252,18 @@
return ErrnoError() << "Can't open " << path;
}
- auto verity_digest = measureFsVerity(fd);
- if (verity_digest.ok()) {
- // The file is already in fs-verity. We need to make sure it was signed
- // by CompOS, so we just check that it has the digest we expect.
- if (verity_digest.value() == compos_digest) {
- ++verified_count;
- } else {
- return Error() << "fs-verity digest does not match CompOS digest: " << path;
- }
- } else {
- // Not in fs-verity yet. We know the digest CompOS provided; If
- // it's not the correct digest for the file then enabling
- // fs-verity will fail, so we don't need to check it explicitly
- // ourselves. Otherwise we should be good.
- LOG(INFO) << "Adding " << path << " to fs-verity...";
+ bool enabled = OR_RETURN(isFileInVerity(fd));
+ if (!enabled) {
+ LOG(INFO) << "Enabling fs-verity for " << path;
+ OR_RETURN(enableFsVerity(fd));
+ }
- auto digest_bytes = fromHex(compos_digest);
- if (digest_bytes.empty()) {
- return Error() << "Invalid digest " << compos_digest;
- }
- auto signed_digest = signDigest(signing_key, digest_bytes);
- if (!signed_digest.ok()) {
- return signed_digest.error();
- }
-
- auto pkcs7_data = createPkcs7(signed_digest.value(), kRootSubject);
- if (!pkcs7_data.ok()) {
- return pkcs7_data.error();
- }
-
- auto enabled = enableFsVerity(fd, pkcs7_data.value());
- if (!enabled.ok()) {
- return Error() << enabled.error();
- }
+ auto actual_digest = OR_RETURN(measureFsVerity(fd));
+ // Make sure the file's fs-verity digest matches the known value.
+ if (actual_digest == compos_digest) {
++verified_count;
+ } else {
+ return Error() << "fs-verity digest does not match CompOS digest: " << path;
}
} else if (it->is_directory()) {
// These are fine to ignore
diff --git a/ondevice-signing/include/VerityUtils.h b/ondevice-signing/include/VerityUtils.h
index e6e49c7..626bbdb 100644
--- a/ondevice-signing/include/VerityUtils.h
+++ b/ondevice-signing/include/VerityUtils.h
@@ -22,11 +22,9 @@
#include <string>
#include <vector>
-#include "SigningKey.h"
-
android::base::Result<void> addCertToFsVerityKeyring(const std::string& path, const char* keyName);
android::base::Result<std::vector<uint8_t>> createDigest(const std::string& path);
-android::base::Result<std::string> enableFsVerity(int fd, const SigningKey& key);
+android::base::Result<std::string> enableFsVerity(int fd);
bool SupportsFsVerity();
android::base::Result<std::map<std::string, std::string>>
verifyAllFilesInVerity(const std::string& path);
@@ -34,13 +32,11 @@
// Note that this function will skip files that are already in fs-verity, and
// for those files it will return the existing digest.
android::base::Result<std::map<std::string, std::string>>
-addFilesToVerityRecursive(const std::string& path, const SigningKey& key);
+addFilesToVerityRecursive(const std::string& path);
// Enable verity on the provided file, using the given PKCS7 signature.
-android::base::Result<void> enableFsVerity(const std::string& path,
- const std::string& signature_path);
+android::base::Result<void> enableFsVerity(const std::string& path);
android::base::Result<void>
verifyAllFilesUsingCompOs(const std::string& directory_path,
- const std::map<std::string, std::string>& digests,
- const SigningKey& signing_key);
+ const std::map<std::string, std::string>& digests);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 93ec3e4..a688ead 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -421,7 +421,7 @@
std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
compos_info->file_hashes().end());
- auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests, signing_key);
+ auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests);
if (!status.ok()) {
LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
} else {
@@ -529,14 +529,6 @@
} else {
LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
}
- auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert, "fsv_ods");
- if (!cert_add_result.ok()) {
- LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
- << cert_add_result.error();
- odsign_record->status =
- art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CERT_FAILED;
- return -1;
- }
}
bool digests_verified = false;
@@ -608,7 +600,7 @@
: art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_PARTIAL_OK;
Result<std::map<std::string, std::string>> digests;
if (supportsFsVerity) {
- digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
+ digests = addFilesToVerityRecursive(kArtArtifactsDir);
} else {
// If we can't use verity, just compute the root hashes and store
// those, so we can reverify them at the next boot.
diff --git a/prng_seeder/Android.bp b/prng_seeder/Android.bp
index 5759731..292535a 100644
--- a/prng_seeder/Android.bp
+++ b/prng_seeder/Android.bp
@@ -31,10 +31,9 @@
],
}
-rust_binary {
- name: "prng_seeder",
+rust_defaults {
+ name: "prng_seeder_defaults",
edition: "2021",
- srcs: ["src/main.rs"],
rustlibs: [
"libanyhow",
"libbssl_ffi",
@@ -48,3 +47,19 @@
init_rc: ["prng_seeder.rc"],
}
+
+rust_binary {
+ name: "prng_seeder",
+ defaults: ["prng_seeder_defaults"],
+ srcs: ["src/main.rs"],
+}
+
+rust_binary {
+ name: "prng_seeder_microdroid",
+ defaults: ["prng_seeder_defaults"],
+ srcs: ["src/main.rs"],
+ stem: "prng_seeder",
+ bootstrap: true,
+ installable: false,
+ prefer_rlib: true,
+}