Merge "Keystore 2.0: Implement onDeviceOffBody."
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 0e8b3d7..5f35444 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -1702,11 +1702,11 @@
],
)
.context("Failed to assign attestation key")?;
- if result != 1 {
- return Err(KsError::sys()).context(format!(
- "Expected to update a single entry but instead updated {}.",
- result
- ));
+ if result == 0 {
+ return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
+ } else if result > 1 {
+ return Err(KsError::sys())
+ .context(format!("Expected to update 1 entry, instead updated {}", result));
}
Ok(()).no_gc()
})
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 26b099a..e212f81 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -656,6 +656,45 @@
}
}
+ScopedAStatus
+KeyMintDevice::convertStorageKeyToEphemeral(const std::vector<uint8_t>& prefixedStorageKeyBlob,
+ std::vector<uint8_t>* ephemeralKeyBlob) {
+ KMV1::ErrorCode km_error;
+
+ /*
+ * Wrapped storage keys cannot be emulated (and they don't need to, because if a platform
+ * supports wrapped storage keys, then the legacy backend will support it too. So error out
+ * if the wrapped storage key given is a soft keymint key.
+ */
+ if (prefixedKeyBlobIsSoftKeyMint(prefixedStorageKeyBlob)) {
+ return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
+ }
+
+ const std::vector<uint8_t>& storageKeyBlob =
+ prefixedKeyBlobRemovePrefix(prefixedStorageKeyBlob);
+
+ auto hidlCb = [&](V4_0_ErrorCode ret, const hidl_vec<uint8_t>& exportedKeyBlob) {
+ km_error = convert(ret);
+ if (km_error != KMV1::ErrorCode::OK) return;
+ /*
+ * This must return the blob without the prefix since it will be used directly
+ * as a storage encryption key. But this is alright, since this wrapped ephemeral
+ * key shouldn't/won't ever be used with keymint.
+ */
+ *ephemeralKeyBlob = exportedKeyBlob;
+ };
+
+ auto ret = mDevice->exportKey(V4_0_KeyFormat::RAW, storageKeyBlob, {}, {}, hidlCb);
+ if (!ret.isOk()) {
+ LOG(ERROR) << __func__ << " export_key failed: " << ret.description();
+ return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
+ }
+ if (km_error != KMV1::ErrorCode::OK)
+ LOG(ERROR) << __func__ << " export_key failed, code " << int32_t(km_error);
+
+ return convertErrorCode(km_error);
+}
+
ScopedAStatus KeyMintDevice::performOperation(const std::vector<uint8_t>& /* request */,
std::vector<uint8_t>* /* response */) {
return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index b48a226..69c24b4 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -115,6 +115,9 @@
const std::optional<TimeStampToken>& timestampToken) override;
ScopedAStatus earlyBootEnded() override;
+ ScopedAStatus convertStorageKeyToEphemeral(const std::vector<uint8_t>& storageKeyBlob,
+ std::vector<uint8_t>* ephemeralKeyBlob) override;
+
ScopedAStatus performOperation(const std::vector<uint8_t>& request,
std::vector<uint8_t>* response) override;
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index b1bb999..f0a4c87 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -193,6 +193,7 @@
/// ```
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
KeyPerm from KeyPermission with default (NONE, none) {
+ CONVERT_STORAGE_KEY_TO_EPHEMERAL, selinux name: convert_storage_key_to_ephemeral;
DELETE, selinux name: delete;
GEN_UNIQUE_ID, selinux name: gen_unique_id;
GET_INFO, selinux name: get_info;
@@ -586,6 +587,7 @@
KeyPerm::rebind(),
KeyPerm::update(),
KeyPerm::use_(),
+ KeyPerm::convert_storage_key_to_ephemeral(),
];
const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
@@ -609,6 +611,7 @@
KeyPerm::rebind(),
KeyPerm::update(),
KeyPerm::use_(),
+ KeyPerm::convert_storage_key_to_ephemeral(),
];
const UNPRIV_PERMS: KeyPermSet = key_perm_set![
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 5a776fb..63b0c74 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -727,6 +727,33 @@
Ok(v) => Ok((v, None)),
}
}
+
+ fn convert_storage_key_to_ephemeral(&self, storage_key: &KeyDescriptor) -> Result<Vec<u8>> {
+ if storage_key.domain != Domain::BLOB {
+ return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT)).context(concat!(
+ "In IKeystoreSecurityLevel convert_storage_key_to_ephemeral: ",
+ "Key must be of Domain::BLOB"
+ ));
+ }
+ let key_blob = storage_key
+ .blob
+ .as_ref()
+ .ok_or(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
+ .context(
+ "In IKeystoreSecurityLevel convert_storage_key_to_ephemeral: No key blob specified",
+ )?;
+
+ // convert_storage_key_to_ephemeral requires the associated permission
+ check_key_permission(KeyPerm::convert_storage_key_to_ephemeral(), storage_key, &None)
+ .context("In convert_storage_key_to_ephemeral: Check permission")?;
+
+ let km_dev: Strong<dyn IKeyMintDevice> = self.keymint.get_interface().context(concat!(
+ "In IKeystoreSecurityLevel convert_storage_key_to_ephemeral: ",
+ "Getting keymint device interface"
+ ))?;
+ map_km_error(km_dev.convertStorageKeyToEphemeral(key_blob))
+ .context("In keymint device convertStorageKeyToEphemeral")
+ }
}
impl binder::Interface for KeystoreSecurityLevel {}
@@ -773,4 +800,10 @@
Ok,
)
}
+ fn convertStorageKeyToEphemeral(
+ &self,
+ storage_key: &KeyDescriptor,
+ ) -> binder::public_api::Result<Vec<u8>> {
+ map_or_log_err(self.convert_storage_key_to_ephemeral(storage_key), Ok)
+ }
}