Merge "Revert "Change extraction tool to vendor_available""
diff --git a/fsverity/fsverity_manifest_generator.py b/fsverity/fsverity_manifest_generator.py
index 79be591..181758a 100644
--- a/fsverity/fsverity_manifest_generator.py
+++ b/fsverity/fsverity_manifest_generator.py
@@ -50,7 +50,7 @@
       required=True)
   p.add_argument(
       'inputs',
-      nargs='+',
+      nargs='*',
       help='input file for the build manifest')
   args = p.parse_args(sys.argv[1:])
 
diff --git a/identity/Android.bp b/identity/Android.bp
index 4e4b79a..9117b7f 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -59,6 +59,7 @@
         "libutilscallstack",
     ],
     static_libs: [
+        "android.hardware.security.rkp-V3-cpp",
         "android.hardware.keymaster-V3-cpp",
         "libcppbor_external",
     ],
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 0e5afd9..51ce9d1 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -31,6 +31,7 @@
     ],
 
     rustlibs: [
+        "android.hardware.security.rkp-V3-rust",
         "android.hardware.security.secureclock-V1-rust",
         "android.hardware.security.sharedsecret-V1-rust",
         "android.os.permissions_aidl-rust",
@@ -84,6 +85,7 @@
         "keystore2_use_latest_aidl_rust",
     ],
     rustlibs: [
+        "android.hardware.security.rkp-V3-rust",
         "libbinder_rs",
         "libkeystore2_selinux",
         "liblog_rust",
@@ -121,6 +123,7 @@
     auto_gen_config: true,
     compile_multilib: "first",
     rustlibs: [
+        "android.hardware.security.rkp-V3-rust",
         "libbinder_rs",
         "libkeystore2_selinux",
         "liblog_rust",
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index d70f210..1e6d4dc 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -24,7 +24,7 @@
 aidl_interface {
     name: "android.security.attestationmanager",
     srcs: [ "android/security/attestationmanager/*.aidl", ],
-    imports: [ "android.hardware.security.keymint-V2" ],
+    imports: [ "android.hardware.security.keymint-V3" ],
     unstable: true,
     backend: {
         java: {
@@ -44,7 +44,7 @@
     name: "android.security.authorization",
     srcs: [ "android/security/authorization/*.aidl" ],
     imports: [
-        "android.hardware.security.keymint-V2",
+        "android.hardware.security.keymint-V3",
         "android.hardware.security.secureclock-V1",
     ],
     unstable: true,
@@ -83,7 +83,7 @@
     name: "android.security.compat",
     srcs: [ "android/security/compat/*.aidl" ],
     imports: [
-        "android.hardware.security.keymint-V2",
+        "android.hardware.security.keymint-V3",
         "android.hardware.security.secureclock-V1",
         "android.hardware.security.sharedsecret-V1",
     ],
@@ -106,7 +106,8 @@
     name: "android.security.remoteprovisioning",
     srcs: [ "android/security/remoteprovisioning/*.aidl" ],
     imports: [
-        "android.hardware.security.keymint-V2",
+        "android.hardware.security.keymint-V3",
+        "android.hardware.security.rkp-V3",
     ],
     unstable: true,
     backend: {
diff --git a/keystore2/apc_compat/Android.bp b/keystore2/apc_compat/Android.bp
index df7521e..61697a8 100644
--- a/keystore2/apc_compat/Android.bp
+++ b/keystore2/apc_compat/Android.bp
@@ -27,7 +27,9 @@
         "apc_compat.cpp",
     ],
     shared_libs: [
+        "libbinder_ndk",
         "android.hardware.confirmationui@1.0",
+        "android.hardware.confirmationui-V1-ndk",
         "libbase",
         "libhidlbase",
         "libutils",
diff --git a/keystore2/apc_compat/apc_compat.cpp b/keystore2/apc_compat/apc_compat.cpp
index 08a8e45..9f60db2 100644
--- a/keystore2/apc_compat/apc_compat.cpp
+++ b/keystore2/apc_compat/apc_compat.cpp
@@ -19,6 +19,12 @@
 #include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
 #include <hwbinder/IBinder.h>
 
+#include <aidl/android/hardware/confirmationui/BnConfirmationResultCallback.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationResultCallback.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationUI.h>
+#include <aidl/android/hardware/confirmationui/UIOption.h>
+#include <android/binder_manager.h>
+
 #include <memory>
 #include <string>
 #include <thread>
@@ -33,41 +39,52 @@
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::hardware::Status;
-using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
-using android::hardware::confirmationui::V1_0::IConfirmationUI;
+using HidlConfirmationResultCb =
+    android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
+using HidlConfirmationUI = android::hardware::confirmationui::V1_0::IConfirmationUI;
 using android::hardware::confirmationui::V1_0::ResponseCode;
-using android::hardware::confirmationui::V1_0::UIOption;
+using HidlUIOptions = android::hardware::confirmationui::V1_0::UIOption;
 
-static uint32_t responseCode2Compat(ResponseCode rc) {
-    switch (rc) {
-    case ResponseCode::OK:
-        return APC_COMPAT_ERROR_OK;
-    case ResponseCode::Canceled:
-        return APC_COMPAT_ERROR_CANCELLED;
-    case ResponseCode::Aborted:
-        return APC_COMPAT_ERROR_ABORTED;
-    case ResponseCode::OperationPending:
-        return APC_COMPAT_ERROR_OPERATION_PENDING;
-    case ResponseCode::Ignored:
-        return APC_COMPAT_ERROR_IGNORED;
-    case ResponseCode::SystemError:
-    case ResponseCode::Unimplemented:
-    case ResponseCode::Unexpected:
-    case ResponseCode::UIError:
-    case ResponseCode::UIErrorMissingGlyph:
-    case ResponseCode::UIErrorMessageTooLong:
-    case ResponseCode::UIErrorMalformedUTF8Encoding:
-    default:
-        return APC_COMPAT_ERROR_SYSTEM_ERROR;
-    }
-}
+using AidlConfirmationUI = ::aidl::android::hardware::confirmationui::IConfirmationUI;
+using AidlBnConfirmationResultCb =
+    ::aidl::android::hardware::confirmationui::BnConfirmationResultCallback;
+using AidlUIOptions = ::aidl::android::hardware::confirmationui::UIOption;
 
-class ConfuiCompatSession : public IConfirmationResultCallback, public hidl_death_recipient {
+class CompatSessionCB {
   public:
-    static sp<ConfuiCompatSession>* tryGetService() {
-        sp<IConfirmationUI> service = IConfirmationUI::tryGetService();
+    void
+    finalize(uint32_t responseCode, ApcCompatCallback callback,
+             std::optional<std::reference_wrapper<const std::vector<uint8_t>>> dataConfirmed,
+             std::optional<std::reference_wrapper<const std::vector<uint8_t>>> confirmationToken) {
+        if (callback.result != nullptr) {
+            size_t dataConfirmedSize = 0;
+            const uint8_t* dataConfirmedPtr = nullptr;
+            size_t confirmationTokenSize = 0;
+            const uint8_t* confirmationTokenPtr = nullptr;
+            if (responseCode == APC_COMPAT_ERROR_OK) {
+                if (dataConfirmed) {
+                    dataConfirmedPtr = dataConfirmed->get().data();
+                    dataConfirmedSize = dataConfirmed->get().size();
+                }
+                if (confirmationToken) {
+                    confirmationTokenPtr = confirmationToken->get().data();
+                    confirmationTokenSize = confirmationToken->get().size();
+                }
+            }
+            callback.result(callback.data, responseCode, dataConfirmedPtr, dataConfirmedSize,
+                            confirmationTokenPtr, confirmationTokenSize);
+        }
+    }
+};
+
+class ConfuiHidlCompatSession : public HidlConfirmationResultCb,
+                                public hidl_death_recipient,
+                                public CompatSessionCB {
+  public:
+    static sp<ConfuiHidlCompatSession> tryGetService() {
+        sp<HidlConfirmationUI> service = HidlConfirmationUI::tryGetService();
         if (service) {
-            return new sp(new ConfuiCompatSession(std::move(service)));
+            return sp<ConfuiHidlCompatSession>(new ConfuiHidlCompatSession(std::move(service)));
         } else {
             return nullptr;
         }
@@ -78,13 +95,12 @@
                                     const char* locale, ApcCompatUiOptions ui_options) {
         std::string hidl_prompt(prompt_text);
         std::vector<uint8_t> hidl_extra(extra_data, extra_data + extra_data_size);
-        std::string hidl_locale(locale);
-        std::vector<UIOption> hidl_ui_options;
+        std::vector<HidlUIOptions> hidl_ui_options;
         if (ui_options.inverted) {
-            hidl_ui_options.push_back(UIOption::AccessibilityInverted);
+            hidl_ui_options.push_back(HidlUIOptions::AccessibilityInverted);
         }
         if (ui_options.magnified) {
-            hidl_ui_options.push_back(UIOption::AccessibilityMagnified);
+            hidl_ui_options.push_back(HidlUIOptions::AccessibilityMagnified);
         }
         auto lock = std::lock_guard(callback_lock_);
         if (callback_.result != nullptr) {
@@ -98,7 +114,7 @@
             return APC_COMPAT_ERROR_SYSTEM_ERROR;
         }
 
-        auto rc = service_->promptUserConfirmation(sp(this), hidl_prompt, hidl_extra, hidl_locale,
+        auto rc = service_->promptUserConfirmation(sp(this), hidl_prompt, hidl_extra, locale,
                                                    hidl_ui_options);
         if (!rc.isOk()) {
             LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.description();
@@ -111,10 +127,8 @@
 
     void abort() { service_->abort(); }
 
-    void
-    finalize(ResponseCode responseCode,
-             std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> dataConfirmed,
-             std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> confirmationToken) {
+    void finalize(ResponseCode responseCode, const hidl_vec<uint8_t>& dataConfirmed,
+                  const hidl_vec<uint8_t>& confirmationToken) {
         ApcCompatCallback callback;
         {
             auto lock = std::lock_guard(callback_lock_);
@@ -128,26 +142,14 @@
         if (callback.result != nullptr) {
             service_->unlinkToDeath(sp(this));
 
-            size_t dataConfirmedSize = 0;
-            const uint8_t* dataConfirmedPtr = nullptr;
-            size_t confirmationTokenSize = 0;
-            const uint8_t* confirmationTokenPtr = nullptr;
-            if (responseCode == ResponseCode::OK) {
-                if (dataConfirmed) {
-                    dataConfirmedPtr = dataConfirmed->get().data();
-                    dataConfirmedSize = dataConfirmed->get().size();
-                }
-                if (dataConfirmed) {
-                    confirmationTokenPtr = confirmationToken->get().data();
-                    confirmationTokenSize = confirmationToken->get().size();
-                }
-            }
-            callback.result(callback.data, responseCode2Compat(responseCode), dataConfirmedPtr,
-                            dataConfirmedSize, confirmationTokenPtr, confirmationTokenSize);
+            std::vector<uint8_t> data = dataConfirmed;
+            std::vector<uint8_t> token = confirmationToken;
+
+            CompatSessionCB::finalize(responseCode2Compat(responseCode), callback, data, token);
         }
     }
 
-    // IConfirmationResultCallback overrides:
+    // HidlConfirmationResultCb overrides:
     android::hardware::Return<void> result(ResponseCode responseCode,
                                            const hidl_vec<uint8_t>& dataConfirmed,
                                            const hidl_vec<uint8_t>& confirmationToken) override {
@@ -160,10 +162,34 @@
         finalize(ResponseCode::SystemError, {}, {});
     }
 
+    static uint32_t responseCode2Compat(ResponseCode rc) {
+        switch (rc) {
+        case ResponseCode::OK:
+            return APC_COMPAT_ERROR_OK;
+        case ResponseCode::Canceled:
+            return APC_COMPAT_ERROR_CANCELLED;
+        case ResponseCode::Aborted:
+            return APC_COMPAT_ERROR_ABORTED;
+        case ResponseCode::OperationPending:
+            return APC_COMPAT_ERROR_OPERATION_PENDING;
+        case ResponseCode::Ignored:
+            return APC_COMPAT_ERROR_IGNORED;
+        case ResponseCode::SystemError:
+        case ResponseCode::Unimplemented:
+        case ResponseCode::Unexpected:
+        case ResponseCode::UIError:
+        case ResponseCode::UIErrorMissingGlyph:
+        case ResponseCode::UIErrorMessageTooLong:
+        case ResponseCode::UIErrorMalformedUTF8Encoding:
+        default:
+            return APC_COMPAT_ERROR_SYSTEM_ERROR;
+        }
+    }
+
   private:
-    ConfuiCompatSession(sp<IConfirmationUI> service)
+    ConfuiHidlCompatSession(sp<HidlConfirmationUI> service)
         : service_(service), callback_{nullptr, nullptr} {}
-    sp<IConfirmationUI> service_;
+    sp<HidlConfirmationUI> service_;
 
     // The callback_lock_ protects the callback_ field against concurrent modification.
     // IMPORTANT: It must never be held while calling the call back.
@@ -171,34 +197,248 @@
     ApcCompatCallback callback_;
 };
 
+class ConfuiAidlCompatSession : public AidlBnConfirmationResultCb, public CompatSessionCB {
+  public:
+    static std::shared_ptr<ConfuiAidlCompatSession> tryGetService() {
+        constexpr const char confirmationUIServiceName[] =
+            "android.hardware.confirmationui.IConfirmationUI/default";
+        if (!AServiceManager_isDeclared(confirmationUIServiceName)) {
+            LOG(INFO) << confirmationUIServiceName << " is not declared in VINTF";
+            return nullptr;
+        }
+        std::shared_ptr<AidlConfirmationUI> aidlService = AidlConfirmationUI::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(confirmationUIServiceName)));
+        if (aidlService) {
+            return ::ndk::SharedRefBase::make<ConfuiAidlCompatSession>(aidlService);
+        }
+
+        return nullptr;
+    }
+
+    uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
+                                    const uint8_t* extra_data, size_t extra_data_size,
+                                    const char* locale, ApcCompatUiOptions ui_options) {
+        std::vector<uint8_t> aidl_prompt(prompt_text, prompt_text + strlen(prompt_text));
+        std::vector<uint8_t> aidl_extra(extra_data, extra_data + extra_data_size);
+        std::vector<AidlUIOptions> aidl_ui_options;
+        if (ui_options.inverted) {
+            aidl_ui_options.push_back(AidlUIOptions::ACCESSIBILITY_INVERTED);
+        }
+        if (ui_options.magnified) {
+            aidl_ui_options.push_back(AidlUIOptions::ACCESSIBILITY_MAGNIFIED);
+        }
+        auto lock = std::lock_guard(callback_lock_);
+        if (callback_.result != nullptr) {
+            return APC_COMPAT_ERROR_OPERATION_PENDING;
+        }
+
+        if (!aidlService_) {
+            return APC_COMPAT_ERROR_SYSTEM_ERROR;
+        }
+        auto linkRet =
+            AIBinder_linkToDeath(aidlService_->asBinder().get(), death_recipient_.get(), this);
+        if (linkRet != STATUS_OK) {
+            LOG(ERROR) << "Communication error: promptUserConfirmation: "
+                          "Trying to register death recipient: ";
+            return APC_COMPAT_ERROR_SYSTEM_ERROR;
+        }
+
+        auto rc = aidlService_->promptUserConfirmation(ref<ConfuiAidlCompatSession>(), aidl_prompt,
+                                                       aidl_extra, locale, aidl_ui_options);
+        int ret = getReturnCode(rc);
+        if (ret == AidlConfirmationUI::OK) {
+            callback_ = callback;
+        } else {
+            LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.getDescription();
+        }
+        return responseCode2Compat(ret);
+    }
+
+    void abort() {
+        if (aidlService_) {
+            aidlService_->abort();
+        }
+    }
+
+    void
+    finalize(int32_t responseCode,
+             std::optional<std::reference_wrapper<const std::vector<uint8_t>>> dataConfirmed,
+             std::optional<std::reference_wrapper<const std::vector<uint8_t>>> confirmationToken) {
+        ApcCompatCallback callback;
+        {
+            auto lock = std::lock_guard(callback_lock_);
+            // Calling the callback consumes the callback data structure. We have to make
+            // sure that it can only be called once.
+            callback = callback_;
+            callback_ = {nullptr, nullptr};
+            // Unlock the callback_lock_ here. It must never be held while calling the callback.
+        }
+
+        if (callback.result != nullptr) {
+            if (aidlService_) {
+                AIBinder_unlinkToDeath(aidlService_->asBinder().get(), death_recipient_.get(),
+                                       this);
+            }
+            CompatSessionCB::finalize(responseCode2Compat(responseCode), callback, dataConfirmed,
+                                      confirmationToken);
+        }
+    }
+
+    // AidlBnConfirmationResultCb overrides:
+    ::ndk::ScopedAStatus result(int32_t responseCode, const std::vector<uint8_t>& dataConfirmed,
+                                const std::vector<uint8_t>& confirmationToken) override {
+        finalize(responseCode, dataConfirmed, confirmationToken);
+        return ::ndk::ScopedAStatus::ok();
+    };
+
+    void serviceDied() {
+        aidlService_.reset();
+        aidlService_ = nullptr;
+        finalize(AidlConfirmationUI::SYSTEM_ERROR, {}, {});
+    }
+
+    static void binderDiedCallbackAidl(void* ptr) {
+        LOG(ERROR) << __func__ << " : ConfuiAidlCompatSession Service died.";
+        auto aidlSession = static_cast<ConfuiAidlCompatSession*>(ptr);
+        if (aidlSession == nullptr) {
+            LOG(ERROR) << __func__ << ": Null ConfuiAidlCompatSession HAL died.";
+            return;
+        }
+        aidlSession->serviceDied();
+    }
+
+    int getReturnCode(const ::ndk::ScopedAStatus& result) {
+        if (result.isOk()) return AidlConfirmationUI::OK;
+
+        if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+            return static_cast<int>(result.getServiceSpecificError());
+        }
+        return result.getStatus();
+    }
+
+    uint32_t responseCode2Compat(int32_t rc) {
+        switch (rc) {
+        case AidlConfirmationUI::OK:
+            return APC_COMPAT_ERROR_OK;
+        case AidlConfirmationUI::CANCELED:
+            return APC_COMPAT_ERROR_CANCELLED;
+        case AidlConfirmationUI::ABORTED:
+            return APC_COMPAT_ERROR_ABORTED;
+        case AidlConfirmationUI::OPERATION_PENDING:
+            return APC_COMPAT_ERROR_OPERATION_PENDING;
+        case AidlConfirmationUI::IGNORED:
+            return APC_COMPAT_ERROR_IGNORED;
+        case AidlConfirmationUI::SYSTEM_ERROR:
+        case AidlConfirmationUI::UNIMPLEMENTED:
+        case AidlConfirmationUI::UNEXPECTED:
+        case AidlConfirmationUI::UI_ERROR:
+        case AidlConfirmationUI::UI_ERROR_MISSING_GLYPH:
+        case AidlConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG:
+        case AidlConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING:
+        default:
+            return APC_COMPAT_ERROR_SYSTEM_ERROR;
+        }
+    }
+
+    ConfuiAidlCompatSession(std::shared_ptr<AidlConfirmationUI> service)
+        : aidlService_(service), callback_{nullptr, nullptr} {
+        death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(binderDiedCallbackAidl));
+    }
+
+    virtual ~ConfuiAidlCompatSession() = default;
+    ConfuiAidlCompatSession(const ConfuiAidlCompatSession&) = delete;
+    ConfuiAidlCompatSession& operator=(const ConfuiAidlCompatSession&) = delete;
+
+  private:
+    std::shared_ptr<AidlConfirmationUI> aidlService_;
+
+    // The callback_lock_ protects the callback_ field against concurrent modification.
+    // IMPORTANT: It must never be held while calling the call back.
+    std::mutex callback_lock_;
+    ApcCompatCallback callback_;
+
+    ::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
+};
+
+class ApcCompatSession {
+  public:
+    static ApcCompatServiceHandle getApcCompatSession() {
+        auto aidlCompatSession = ConfuiAidlCompatSession::tryGetService();
+        if (aidlCompatSession) {
+            return new ApcCompatSession(std::move(aidlCompatSession), nullptr);
+        }
+
+        sp<ConfuiHidlCompatSession> hidlCompatSession = ConfuiHidlCompatSession::tryGetService();
+        if (hidlCompatSession) {
+            return new ApcCompatSession(nullptr, std::move(hidlCompatSession));
+        }
+
+        LOG(ERROR) << "ConfirmationUI: Not found Service";
+        return nullptr;
+    }
+
+    uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
+                                    const uint8_t* extra_data, size_t extra_data_size,
+                                    char const* locale, ApcCompatUiOptions ui_options) {
+        if (aidlCompatSession_) {
+            return aidlCompatSession_->promptUserConfirmation(callback, prompt_text, extra_data,
+                                                              extra_data_size, locale, ui_options);
+        } else {
+            return hidlCompatSession_->promptUserConfirmation(callback, prompt_text, extra_data,
+                                                              extra_data_size, locale, ui_options);
+        }
+    }
+
+    void abortUserConfirmation() {
+        if (aidlCompatSession_) {
+            return aidlCompatSession_->abort();
+        } else {
+            return hidlCompatSession_->abort();
+        }
+    }
+
+    void closeUserConfirmationService() {
+        // Closing the handle implicitly aborts an ongoing sessions.
+        // Note that a resulting callback is still safely conducted, because we only delete a
+        // StrongPointer below. libhwbinder still owns another StrongPointer to this session.
+        abortUserConfirmation();
+    }
+
+    ApcCompatSession(std::shared_ptr<ConfuiAidlCompatSession> aidlCompatSession,
+                     sp<ConfuiHidlCompatSession> hidlCompatSession)
+        : aidlCompatSession_(aidlCompatSession), hidlCompatSession_(hidlCompatSession) {}
+
+  private:
+    std::shared_ptr<ConfuiAidlCompatSession> aidlCompatSession_;
+    sp<ConfuiHidlCompatSession> hidlCompatSession_;
+};
 }  // namespace keystore2
 
 using namespace keystore2;
 
 ApcCompatServiceHandle tryGetUserConfirmationService() {
-    return reinterpret_cast<ApcCompatServiceHandle>(ConfuiCompatSession::tryGetService());
+    return reinterpret_cast<ApcCompatServiceHandle>(ApcCompatSession::getApcCompatSession());
 }
 
 uint32_t promptUserConfirmation(ApcCompatServiceHandle handle, ApcCompatCallback callback,
                                 const char* prompt_text, const uint8_t* extra_data,
                                 size_t extra_data_size, char const* locale,
                                 ApcCompatUiOptions ui_options) {
-    auto session = reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
-    return (*session)->promptUserConfirmation(callback, prompt_text, extra_data, extra_data_size,
-                                              locale, ui_options);
+    auto session = reinterpret_cast<ApcCompatSession*>(handle);
+    return session->promptUserConfirmation(callback, prompt_text, extra_data, extra_data_size,
+                                           locale, ui_options);
 }
 
 void abortUserConfirmation(ApcCompatServiceHandle handle) {
-    auto session = reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
-    (*session)->abort();
+    auto session = reinterpret_cast<ApcCompatSession*>(handle);
+    session->abortUserConfirmation();
 }
 
 void closeUserConfirmationService(ApcCompatServiceHandle handle) {
-    // Closing the handle implicitly aborts an ongoing sessions.
-    // Note that a resulting callback is still safely conducted, because we only delete a
-    // StrongPointer below. libhwbinder still owns another StrongPointer to this session.
-    abortUserConfirmation(handle);
-    delete reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
+    auto session = reinterpret_cast<ApcCompatSession*>(handle);
+    session->closeUserConfirmationService();
+    delete reinterpret_cast<ApcCompatSession*>(handle);
 }
 
 const ApcCompatServiceHandle INVALID_SERVICE_HANDLE = nullptr;
diff --git a/keystore2/src/apc.rs b/keystore2/src/apc.rs
index 1dc14ea..5d2083d 100644
--- a/keystore2/src/apc.rs
+++ b/keystore2/src/apc.rs
@@ -22,6 +22,7 @@
 };
 
 use crate::error::anyhow_error_to_cstring;
+use crate::ks_err;
 use crate::utils::{compat_2_response_code, ui_opts_2_compat, watchdog as wd};
 use android_security_apc::aidl::android::security::apc::{
     IConfirmationCallback::IConfirmationCallback,
@@ -259,13 +260,10 @@
 
         if let Ok(listener) = callback.into_interface::<dyn IConfirmationCallback>() {
             if let Err(e) = listener.onCompleted(rc, data_confirmed) {
-                log::error!(
-                    "In ApcManagerCallback::result: Reporting completion to client failed {:?}",
-                    e
-                )
+                log::error!("Reporting completion to client failed {:?}", e)
             }
         } else {
-            log::error!("In ApcManagerCallback::result: SpIBinder is not a IConfirmationCallback.");
+            log::error!("SpIBinder is not a IConfirmationCallback.");
         }
     }
 
@@ -279,8 +277,7 @@
     ) -> Result<()> {
         let mut state = self.state.lock().unwrap();
         if state.session.is_some() {
-            return Err(Error::pending())
-                .context("In ApcManager::present_prompt: Session pending.");
+            return Err(Error::pending()).context(ks_err!("APC Session pending."));
         }
 
         // Perform rate limiting.
@@ -289,8 +286,8 @@
             None => {}
             Some(rate_info) => {
                 if let Some(back_off) = rate_info.get_remaining_back_off() {
-                    return Err(Error::sys()).context(format!(
-                        "In ApcManager::present_prompt: Cooling down. Remaining back-off: {}s",
+                    return Err(Error::sys()).context(ks_err!(
+                        "APC Cooling down. Remaining back-off: {}s",
                         back_off.as_secs()
                     ));
                 }
@@ -300,8 +297,7 @@
         let hal = ApcHal::try_get_service();
         let hal = match hal {
             None => {
-                return Err(Error::unimplemented())
-                    .context("In ApcManager::present_prompt: APC not supported.")
+                return Err(Error::unimplemented()).context(ks_err!("APC not supported."));
             }
             Some(h) => Arc::new(h),
         };
@@ -319,7 +315,7 @@
             },
         )
         .map_err(|rc| Error::Rc(compat_2_response_code(rc)))
-        .context("In present_prompt: Failed to present prompt.")?;
+        .context(ks_err!("APC Failed to present prompt."))?;
         state.session = Some(ApcSessionState {
             hal,
             cb: listener.as_binder(),
@@ -335,13 +331,12 @@
         let hal = match &mut state.session {
             None => {
                 return Err(Error::ignored())
-                    .context("In cancel_prompt: Attempt to cancel non existing session. Ignoring.")
+                    .context(ks_err!("Attempt to cancel non existing session. Ignoring."));
             }
             Some(session) => {
                 if session.cb != listener.as_binder() {
-                    return Err(Error::ignored()).context(concat!(
-                        "In cancel_prompt: Attempt to cancel session not belonging to caller. ",
-                        "Ignoring."
+                    return Err(Error::ignored()).context(ks_err!(
+                        "Attempt to cancel session not belonging to caller. Ignoring."
                     ));
                 }
                 session.client_aborted = true;
diff --git a/keystore2/src/attestation_key_utils.rs b/keystore2/src/attestation_key_utils.rs
index 3408942..94f3e4c 100644
--- a/keystore2/src/attestation_key_utils.rs
+++ b/keystore2/src/attestation_key_utils.rs
@@ -18,6 +18,7 @@
 use crate::database::{BlobMetaData, KeyEntryLoadBits, KeyType};
 use crate::database::{KeyIdGuard, KeystoreDB};
 use crate::error::{Error, ErrorCode};
+use crate::ks_err;
 use crate::permission::KeyPerm;
 use crate::remote_provisioning::RemProvState;
 use crate::utils::check_key_permission;
@@ -25,7 +26,7 @@
     AttestationKey::AttestationKey, Certificate::Certificate, KeyParameter::KeyParameter, Tag::Tag,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    Domain::Domain, KeyDescriptor::KeyDescriptor,
+    Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
 };
 use anyhow::{Context, Result};
 use keystore2_crypto::parse_subject_from_certificate;
@@ -65,10 +66,7 @@
         // 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(concat!(
-                "In get_attest_key_and_cert_chain: ",
-                "Trying to get remotely provisioned attestation key."
-            ))
+            .context(ks_err!("Trying to get remotely provisioned attestation key."))
             .map(|result| {
                 result.map(|(key_id_guard, attestation_key, attestation_certs)| {
                     AttestationKeyInfo::RemoteProvisioned {
@@ -80,7 +78,7 @@
             }),
         None => Ok(None),
         Some(attest_key) => get_user_generated_attestation_key(attest_key, caller_uid, db)
-            .context("In get_attest_key_and_cert_chain: Trying to load attest key")
+            .context(ks_err!("Trying to load attest key"))
             .map(Some),
     }
 }
@@ -92,11 +90,10 @@
 ) -> Result<AttestationKeyInfo> {
     let (key_id_guard, blob, cert, blob_metadata) =
         load_attest_key_blob_and_cert(key, caller_uid, db)
-            .context("In get_user_generated_attestation_key: Failed to load blob and cert")?;
+            .context(ks_err!("Failed to load blob and cert"))?;
 
-    let issuer_subject: Vec<u8> = parse_subject_from_certificate(&cert).context(
-        "In get_user_generated_attestation_key: Failed to parse subject from certificate.",
-    )?;
+    let issuer_subject: Vec<u8> = parse_subject_from_certificate(&cert)
+        .context(ks_err!("Failed to parse subject from certificate"))?;
 
     Ok(AttestationKeyInfo::UserGenerated { key_id_guard, blob, issuer_subject, blob_metadata })
 }
@@ -107,9 +104,8 @@
     db: &mut KeystoreDB,
 ) -> Result<(KeyIdGuard, Vec<u8>, Vec<u8>, BlobMetaData)> {
     match key.domain {
-        Domain::BLOB => Err(Error::Km(ErrorCode::INVALID_ARGUMENT)).context(
-            "In load_attest_key_blob_and_cert: Domain::BLOB attestation keys not supported",
-        ),
+        Domain::BLOB => Err(Error::Km(ErrorCode::INVALID_ARGUMENT))
+            .context(ks_err!("Domain::BLOB attestation keys not supported")),
         _ => {
             let (key_id_guard, mut key_entry) = db
                 .load_key_entry(
@@ -119,17 +115,16 @@
                     caller_uid,
                     |k, av| check_key_permission(KeyPerm::Use, k, &av),
                 )
-                .context("In load_attest_key_blob_and_cert: Failed to load key.")?;
+                .context(ks_err!("Failed to load key."))?;
 
-            let (blob, blob_metadata) =
-                key_entry.take_key_blob_info().ok_or_else(Error::sys).context(concat!(
-                    "In load_attest_key_blob_and_cert: Successfully loaded key entry,",
-                    " but KM blob was missing."
-                ))?;
-            let cert = key_entry.take_cert().ok_or_else(Error::sys).context(concat!(
-                "In load_attest_key_blob_and_cert: Successfully loaded key entry,",
-                " but cert was missing."
-            ))?;
+            let (blob, blob_metadata) = key_entry
+                .take_key_blob_info()
+                .ok_or(Error::Rc(ResponseCode::INVALID_ARGUMENT))
+                .context(ks_err!("Successfully loaded key entry, but KM blob was missing"))?;
+            let cert = key_entry
+                .take_cert()
+                .ok_or(Error::Rc(ResponseCode::INVALID_ARGUMENT))
+                .context(ks_err!("Successfully loaded key entry, but cert was missing"))?;
             Ok((key_id_guard, blob, cert, blob_metadata))
         }
     }
diff --git a/keystore2/src/audit_log.rs b/keystore2/src/audit_log.rs
index 3d7d26e..07509d3 100644
--- a/keystore2/src/audit_log.rs
+++ b/keystore2/src/audit_log.rs
@@ -67,7 +67,7 @@
 fn log_key_event(tag: u32, key: &KeyDescriptor, calling_app: uid_t, success: bool) {
     with_log_context(tag, |ctx| {
         let owner = key_owner(key.domain, key.nspace, calling_app as i32);
-        ctx.append_i32(if success { 1 } else { 0 })
+        ctx.append_i32(i32::from(success))
             .append_str(key.alias.as_ref().map_or("none", String::as_str))
             .append_i32(owner)
     })
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 666daeb..1953920 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -14,6 +14,7 @@
 
 //! This module implements IKeystoreAuthorization AIDL interface.
 
+use crate::ks_err;
 use crate::error::Error as KeystoreError;
 use crate::error::anyhow_error_to_cstring;
 use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_IMPORTER};
@@ -23,15 +24,15 @@
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     HardwareAuthToken::HardwareAuthToken,
 };
-use android_security_authorization::binder::{BinderFeatures,ExceptionCode, Interface, Result as BinderResult,
-     Strong, Status as BinderStatus};
+use android_security_authorization::binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult,
+    Strong, Status as BinderStatus};
 use android_security_authorization::aidl::android::security::authorization::{
     IKeystoreAuthorization::BnKeystoreAuthorization, IKeystoreAuthorization::IKeystoreAuthorization,
     LockScreenEvent::LockScreenEvent, AuthorizationTokens::AuthorizationTokens,
     ResponseCode::ResponseCode,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    ResponseCode::ResponseCode as KsResponseCode };
+    ResponseCode::ResponseCode as KsResponseCode};
 use anyhow::{Context, Result};
 use keystore2_crypto::Password;
 use keystore2_selinux as selinux;
@@ -126,7 +127,7 @@
 
     fn add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()> {
         // Check keystore permission.
-        check_keystore_permission(KeystorePerm::AddAuth).context("In add_auth_token.")?;
+        check_keystore_permission(KeystorePerm::AddAuth).context(ks_err!())?;
 
         ENFORCEMENTS.add_auth_token(auth_token.clone());
         Ok(())
@@ -151,7 +152,7 @@
                 // This corresponds to the unlock() method in legacy keystore API.
                 // check permission
                 check_keystore_permission(KeystorePerm::Unlock)
-                    .context("In on_lock_screen_event: Unlock with password.")?;
+                    .context(ks_err!("Unlock with password."))?;
                 ENFORCEMENTS.set_device_locked(user_id, false);
 
                 let mut skm = SUPER_KEY.write().unwrap();
@@ -163,7 +164,7 @@
                         &password,
                     )
                 })
-                .context("In on_lock_screen_event: unlock_screen_lock_bound_key failed")?;
+                .context(ks_err!("unlock_screen_lock_bound_key failed"))?;
 
                 // Unlock super key.
                 if let UserState::Uninitialized = DB
@@ -175,7 +176,7 @@
                             &password,
                         )
                     })
-                    .context("In on_lock_screen_event: Unlock with password.")?
+                    .context(ks_err!("Unlock with password."))?
                 {
                     log::info!(
                         "In on_lock_screen_event. Trying to unlock when LSKF is uninitialized."
@@ -185,19 +186,17 @@
                 Ok(())
             }
             (LockScreenEvent::UNLOCK, None) => {
-                check_keystore_permission(KeystorePerm::Unlock)
-                    .context("In on_lock_screen_event: Unlock.")?;
+                check_keystore_permission(KeystorePerm::Unlock).context(ks_err!("Unlock."))?;
                 ENFORCEMENTS.set_device_locked(user_id, false);
                 let mut skm = SUPER_KEY.write().unwrap();
                 DB.with(|db| {
                     skm.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32)
                 })
-                .context("In on_lock_screen_event: try_unlock_user_with_biometric failed")?;
+                .context(ks_err!("try_unlock_user_with_biometric failed"))?;
                 Ok(())
             }
             (LockScreenEvent::LOCK, None) => {
-                check_keystore_permission(KeystorePerm::Lock)
-                    .context("In on_lock_screen_event: Lock")?;
+                check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?;
                 ENFORCEMENTS.set_device_locked(user_id, true);
                 let mut skm = SUPER_KEY.write().unwrap();
                 DB.with(|db| {
@@ -211,8 +210,7 @@
             }
             _ => {
                 // Any other combination is not supported.
-                Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
-                    .context("In on_lock_screen_event: Unknown event.")
+                Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!("Unknown event."))
             }
         }
     }
@@ -225,13 +223,12 @@
     ) -> Result<AuthorizationTokens> {
         // Check permission. Function should return if this failed. Therefore having '?' at the end
         // is very important.
-        check_keystore_permission(KeystorePerm::GetAuthToken)
-            .context("In get_auth_tokens_for_credstore.")?;
+        check_keystore_permission(KeystorePerm::GetAuthToken).context(ks_err!("GetAuthToken"))?;
 
         // If the challenge is zero, return error
         if challenge == 0 {
             return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
-                .context("In get_auth_tokens_for_credstore. Challenge can not be zero.");
+                .context(ks_err!("Challenge can not be zero."));
         }
         // Obtain the auth token and the timestamp token from the enforcement module.
         let (auth_token, ts_token) =
diff --git a/keystore2/src/boot_level_keys.rs b/keystore2/src/boot_level_keys.rs
index 237d7d2..e2e67ff 100644
--- a/keystore2/src/boot_level_keys.rs
+++ b/keystore2/src/boot_level_keys.rs
@@ -14,6 +14,7 @@
 
 //! Offer keys based on the "boot level" for superencryption.
 
+use crate::ks_err;
 use crate::{
     database::{KeyType, KeystoreDB},
     key_parameter::KeyParameterValue,
@@ -47,9 +48,8 @@
 const PROPERTY_NAME: &str = "ro.keystore.boot_level_key.strategy";
 
 fn lookup_level_zero_km_and_strategy() -> Result<Option<(SecurityLevel, DenyLaterStrategy)>> {
-    let property_val = rustutils::system_properties::read(PROPERTY_NAME).with_context(|| {
-        format!("In lookup_level_zero_km_and_strategy: property read failed: {}", PROPERTY_NAME)
-    })?;
+    let property_val = rustutils::system_properties::read(PROPERTY_NAME)
+        .with_context(|| ks_err!("property read failed: {}", PROPERTY_NAME))?;
     // TODO: use feature(let_else) when that's stabilized.
     let property_val = if let Some(p) = property_val {
         p
@@ -86,18 +86,17 @@
 fn get_level_zero_key_km_and_strategy() -> Result<(KeyMintDevice, DenyLaterStrategy)> {
     if let Some((level, strategy)) = lookup_level_zero_km_and_strategy()? {
         return Ok((
-            KeyMintDevice::get(level)
-                .context("In get_level_zero_key_km_and_strategy: Get KM instance failed.")?,
+            KeyMintDevice::get(level).context(ks_err!("Get KM instance failed."))?,
             strategy,
         ));
     }
     let tee = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
-        .context("In get_level_zero_key_km_and_strategy: Get TEE instance failed.")?;
+        .context(ks_err!("Get TEE instance failed."))?;
     if tee.version() >= KeyMintDevice::KEY_MASTER_V4_1 {
         Ok((tee, DenyLaterStrategy::EarlyBootOnly))
     } else {
         match KeyMintDevice::get_or_none(SecurityLevel::STRONGBOX)
-            .context("In get_level_zero_key_km_and_strategy: Get Strongbox instance failed.")?
+            .context(ks_err!("Get Strongbox instance failed."))?
         {
             Some(strongbox) if strongbox.version() >= KeyMintDevice::KEY_MASTER_V4_1 => {
                 Ok((strongbox, DenyLaterStrategy::EarlyBootOnly))
@@ -112,7 +111,7 @@
 /// Mutex on its internal state.
 pub fn get_level_zero_key(db: &mut KeystoreDB) -> Result<ZVec> {
     let (km_dev, deny_later_strategy) = get_level_zero_key_km_and_strategy()
-        .context("In get_level_zero_key: get preferred KM instance failed")?;
+        .context(ks_err!("get preferred KM instance failed"))?;
     log::info!(
         "In get_level_zero_key: security_level={:?}, deny_later_strategy={:?}",
         km_dev.security_level(),
@@ -156,7 +155,7 @@
                 true
             })
         })
-        .context("In get_level_zero_key: lookup_or_generate_key failed")?;
+        .context(ks_err!("lookup_or_generate_key failed"))?;
 
     let params = [
         KeyParameterValue::MacLength(256).into(),
@@ -172,11 +171,11 @@
             None,
             b"Create boot level key",
         )
-        .context("In get_level_zero_key: use_key_in_one_step failed")?;
+        .context(ks_err!("use_key_in_one_step failed"))?;
     // TODO: this is rather unsatisfactory, we need a better way to handle
     // sensitive binder returns.
-    let level_zero_key = ZVec::try_from(level_zero_key)
-        .context("In get_level_zero_key: conversion to ZVec failed")?;
+    let level_zero_key =
+        ZVec::try_from(level_zero_key).context(ks_err!("conversion to ZVec failed"))?;
     Ok(level_zero_key)
 }
 
@@ -228,7 +227,7 @@
             // so this must unwrap.
             let highest_key = self.cache.back().unwrap();
             let next_key = hkdf_expand(Self::HKDF_KEY_SIZE, highest_key, Self::HKDF_ADVANCE)
-                .context("In BootLevelKeyCache::get_hkdf_key: Advancing key one step")?;
+                .context(ks_err!("Advancing key one step"))?;
             self.cache.push_back(next_key);
         }
 
@@ -241,10 +240,7 @@
     pub fn advance_boot_level(&mut self, new_boot_level: usize) -> Result<()> {
         if !self.level_accessible(new_boot_level) {
             log::error!(
-                concat!(
-                    "In BootLevelKeyCache::advance_boot_level: ",
-                    "Failed to advance boot level to {}, current is {}, cache size {}"
-                ),
+                "Failed to advance boot level to {}, current is {}, cache size {}",
                 new_boot_level,
                 self.current,
                 self.cache.len()
@@ -254,8 +250,7 @@
 
         // We `get` the new boot level for the side effect of advancing the cache to a point
         // where the new boot level is present.
-        self.get_hkdf_key(new_boot_level)
-            .context("In BootLevelKeyCache::advance_boot_level: Advancing cache")?;
+        self.get_hkdf_key(new_boot_level).context(ks_err!("Advancing cache"))?;
 
         // Then we split the queue at the index of the new boot level and discard the front,
         // keeping only the keys with the current boot level or higher.
@@ -281,16 +276,16 @@
         info: &[u8],
     ) -> Result<Option<ZVec>> {
         self.get_hkdf_key(boot_level)
-            .context("In BootLevelKeyCache::expand_key: Looking up HKDF key")?
+            .context(ks_err!("Looking up HKDF key"))?
             .map(|k| hkdf_expand(out_len, k, info))
             .transpose()
-            .context("In BootLevelKeyCache::expand_key: Calling hkdf_expand")
+            .context(ks_err!("Calling hkdf_expand"))
     }
 
     /// Return the AES-256-GCM key for the current boot level.
     pub fn aes_key(&mut self, boot_level: usize) -> Result<Option<ZVec>> {
         self.expand_key(boot_level, AES_256_KEY_LENGTH, BootLevelKeyCache::HKDF_AES)
-            .context("In BootLevelKeyCache::aes_key: expand_key failed")
+            .context(ks_err!("expand_key failed"))
     }
 }
 
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 5cdfbe9..dbdb4e6 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -49,6 +49,7 @@
 use crate::globals::get_keymint_dev_by_uuid;
 use crate::impl_metadata; // This is in db_utils.rs
 use crate::key_parameter::{KeyParameter, Tag};
+use crate::ks_err;
 use crate::metrics_store::log_rkp_error_stats;
 use crate::permission::KeyPermSet;
 use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, AID_USER_OFFSET};
@@ -133,12 +134,13 @@
                 "SELECT tag, data from persistent.keymetadata
                     WHERE keyentryid = ?;",
             )
-            .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
+            .context(ks_err!("KeyMetaData::load_from_db: prepare statement failed."))?;
 
         let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
 
-        let mut rows =
-            stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
+        let mut rows = stmt
+            .query(params![key_id])
+            .context(ks_err!("KeyMetaData::load_from_db: query failed."))?;
         db_utils::with_rows_extract_all(&mut rows, |row| {
             let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
             metadata.insert(
@@ -148,7 +150,7 @@
             );
             Ok(())
         })
-        .context("In KeyMetaData::load_from_db.")?;
+        .context(ks_err!("KeyMetaData::load_from_db."))?;
 
         Ok(Self { data: metadata })
     }
@@ -159,12 +161,12 @@
                 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
                     VALUES (?, ?, ?);",
             )
-            .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
+            .context(ks_err!("KeyMetaData::store_in_db: Failed to prepare statement."))?;
 
         let iter = self.data.iter();
         for (tag, entry) in iter {
             stmt.insert(params![key_id, tag, entry,]).with_context(|| {
-                format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
+                ks_err!("KeyMetaData::store_in_db: Failed to insert {:?}", entry)
             })?;
         }
         Ok(())
@@ -208,12 +210,11 @@
                 "SELECT tag, data from persistent.blobmetadata
                     WHERE blobentryid = ?;",
             )
-            .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
+            .context(ks_err!("BlobMetaData::load_from_db: prepare statement failed."))?;
 
         let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
 
-        let mut rows =
-            stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
+        let mut rows = stmt.query(params![blob_id]).context(ks_err!("query failed."))?;
         db_utils::with_rows_extract_all(&mut rows, |row| {
             let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
             metadata.insert(
@@ -223,7 +224,7 @@
             );
             Ok(())
         })
-        .context("In BlobMetaData::load_from_db.")?;
+        .context(ks_err!("BlobMetaData::load_from_db"))?;
 
         Ok(Self { data: metadata })
     }
@@ -234,12 +235,12 @@
                 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
                     VALUES (?, ?, ?);",
             )
-            .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
+            .context(ks_err!("BlobMetaData::store_in_db: Failed to prepare statement.",))?;
 
         let iter = self.data.iter();
         for (tag, entry) in iter {
             stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
-                format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
+                ks_err!("BlobMetaData::store_in_db: Failed to insert {:?}", entry)
             })?;
         }
         Ok(())
@@ -881,7 +882,7 @@
         let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
         db.with_transaction(TransactionBehavior::Immediate, |tx| {
             versioning::upgrade_database(tx, Self::CURRENT_DB_VERSION, Self::UPGRADERS)
-                .context("In KeystoreDB::new: trying to upgrade database.")?;
+                .context(ks_err!("KeystoreDB::new: trying to upgrade database."))?;
             Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
         })?;
         Ok(db)
@@ -903,7 +904,7 @@
                  );",
             params![KeyLifeCycle::Unreferenced, Tag::MAX_BOOT_LEVEL.0, BlobMetaData::MaxBootLevel],
         )
-        .context("In from_0_to_1: Failed to delete logical boot level keys.")?;
+        .context(ks_err!("Failed to delete logical boot level keys."))?;
         Ok(1)
     }
 
@@ -1064,7 +1065,7 @@
         let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
             tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
                 .with_context(|| {
-                    format!("get_storage_stat: Error size of storage type {}", storage_type.0)
+                    ks_err!("get_storage_stat: Error size of storage type {}", storage_type.0)
                 })
                 .no_gc()
         })?;
@@ -1239,7 +1240,7 @@
 
             Ok(vec![]).no_gc()
         })
-        .context("In handle_next_superseded_blobs.")
+        .context(ks_err!())
     }
 
     /// This maintenance function should be called only once before the database is used for the
@@ -1261,7 +1262,7 @@
             .context("Failed to execute query.")
             .need_gc()
         })
-        .context("In cleanup_leftovers.")
+        .context(ks_err!())
     }
 
     /// Checks if a key exists with given key type and key descriptor properties.
@@ -1282,12 +1283,12 @@
                 Ok(_) => Ok(true),
                 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
                     Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
-                    _ => Err(error).context("In key_exists: Failed to find if the key exists."),
+                    _ => Err(error).context(ks_err!("Failed to find if the key exists.")),
                 },
             }
             .no_gc()
         })
-        .context("In key_exists.")
+        .context(ks_err!())
     }
 
     /// Stores a super key in the database.
@@ -1335,7 +1336,7 @@
                 .context("Trying to load key components.")
                 .no_gc()
         })
-        .context("In store_super_key.")
+        .context(ks_err!())
     }
 
     /// Loads super key of a given user, if exists
@@ -1357,17 +1358,17 @@
             match id {
                 Ok(id) => {
                     let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
-                        .context("In load_super_key. Failed to load key entry.")?;
+                        .context(ks_err!("Failed to load key entry."))?;
                     Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
                 }
                 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
                     Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
-                    _ => Err(error).context("In load_super_key."),
+                    _ => Err(error).context(ks_err!()),
                 },
             }
             .no_gc()
         })
-        .context("In load_super_key.")
+        .context(ks_err!())
     }
 
     /// Atomically loads a key entry and associated metadata or creates it using the
@@ -1399,10 +1400,10 @@
                     AND alias = ?
                     AND state = ?;",
                     )
-                    .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
+                    .context(ks_err!("Failed to select from keyentry table."))?;
                 let mut rows = stmt
                     .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
-                    .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
+                    .context(ks_err!("Failed to query from keyentry table."))?;
 
                 db_utils::with_rows_extract_one(&mut rows, |row| {
                     Ok(match row {
@@ -1410,14 +1411,13 @@
                         None => None,
                     })
                 })
-                .context("In get_or_create_key_with.")?
+                .context(ks_err!())?
             };
 
             let (id, entry) = match id {
                 Some(id) => (
                     id,
-                    Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
-                        .context("In get_or_create_key_with.")?,
+                    Self::load_key_components(tx, KeyEntryLoadBits::KM, id).context(ks_err!())?,
                 ),
 
                 None => {
@@ -1437,10 +1437,9 @@
                             ],
                         )
                     })
-                    .context("In get_or_create_key_with.")?;
+                    .context(ks_err!())?;
 
-                    let (blob, metadata) =
-                        create_new_key().context("In get_or_create_key_with.")?;
+                    let (blob, metadata) = create_new_key().context(ks_err!())?;
                     Self::set_blob_internal(
                         tx,
                         id,
@@ -1448,7 +1447,7 @@
                         Some(&blob),
                         Some(&metadata),
                     )
-                    .context("In get_or_create_key_with.")?;
+                    .context(ks_err!())?;
                     (
                         id,
                         KeyEntry {
@@ -1462,7 +1461,7 @@
             };
             Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
         })
-        .context("In get_or_create_key_with.")
+        .context(ks_err!())
     }
 
     /// Creates a transaction with the given behavior and executes f with the new transaction.
@@ -1476,10 +1475,10 @@
             match self
                 .conn
                 .transaction_with_behavior(behavior)
-                .context("In with_transaction.")
+                .context(ks_err!())
                 .and_then(|tx| f(&tx).map(|result| (result, tx)))
                 .and_then(|(result, tx)| {
-                    tx.commit().context("In with_transaction: Failed to commit transaction.")?;
+                    tx.commit().context(ks_err!("Failed to commit transaction."))?;
                     Ok(result)
                 }) {
                 Ok(result) => break Ok(result),
@@ -1488,7 +1487,7 @@
                         std::thread::sleep(std::time::Duration::from_micros(500));
                         continue;
                     } else {
-                        return Err(e).context("In with_transaction.");
+                        return Err(e).context(ks_err!());
                     }
                 }
             }
@@ -1529,7 +1528,7 @@
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             Self::create_key_entry_internal(tx, domain, namespace, key_type, km_uuid).no_gc()
         })
-        .context("In create_key_entry.")
+        .context(ks_err!())
     }
 
     fn create_key_entry_internal(
@@ -1543,7 +1542,7 @@
             Domain::APP | Domain::SELINUX => {}
             _ => {
                 return Err(KsError::sys())
-                    .context(format!("Domain {:?} must be either App or SELinux.", domain));
+                    .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
             }
         }
         Ok(KEY_ID_LOCK.get(
@@ -1562,7 +1561,7 @@
                     ],
                 )
             })
-            .context("In create_key_entry_internal")?,
+            .context(ks_err!())?,
         ))
     }
 
@@ -1590,7 +1589,7 @@
                         params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
                     )
                 })
-                .context("In create_key_entry")?,
+                .context(ks_err!())?,
             );
             Self::set_blob_internal(
                 tx,
@@ -1605,7 +1604,7 @@
             metadata.store_in_db(key_id.0, tx)?;
             Ok(()).no_gc()
         })
-        .context("In create_attestation_key_entry")
+        .context(ks_err!())
     }
 
     /// Set a new blob and associates it with the given key id. Each blob
@@ -1627,7 +1626,7 @@
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             Self::set_blob_internal(tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
         })
-        .context("In set_blob.")
+        .context(ks_err!())
     }
 
     /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
@@ -1647,7 +1646,7 @@
             )
             .need_gc()
         })
-        .context("In set_deleted_blob.")
+        .context(ks_err!())
     }
 
     fn set_blob_internal(
@@ -1664,16 +1663,16 @@
                      (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
                     params![sc_type, key_id, blob],
                 )
-                .context("In set_blob_internal: Failed to insert blob.")?;
+                .context(ks_err!("Failed to insert blob."))?;
                 if let Some(blob_metadata) = blob_metadata {
                     let blob_id = tx
                         .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
                             row.get(0)
                         })
-                        .context("In set_blob_internal: Failed to get new blob id.")?;
+                        .context(ks_err!("Failed to get new blob id."))?;
                     blob_metadata
                         .store_in_db(blob_id, tx)
-                        .context("In set_blob_internal: Trying to store blob metadata.")?;
+                        .context(ks_err!("Trying to store blob metadata."))?;
                 }
             }
             (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
@@ -1682,11 +1681,11 @@
                     WHERE subcomponent_type = ? AND keyentryid = ?;",
                     params![sc_type, key_id],
                 )
-                .context("In set_blob_internal: Failed to delete blob.")?;
+                .context(ks_err!("Failed to delete blob."))?;
             }
             (None, _) => {
                 return Err(KsError::sys())
-                    .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
+                    .context(ks_err!("Other blobs cannot be deleted in this way."));
             }
         }
         Ok(())
@@ -1699,7 +1698,7 @@
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
         })
-        .context("In insert_keyparameter.")
+        .context(ks_err!())
     }
 
     fn insert_keyparameter_internal(
@@ -1712,7 +1711,7 @@
                 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
                 VALUES (?, ?, ?, ?);",
             )
-            .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
+            .context(ks_err!("Failed to prepare statement."))?;
 
         for p in params.iter() {
             stmt.insert(params![
@@ -1721,9 +1720,7 @@
                 p.key_parameter_value(),
                 p.security_level().0
             ])
-            .with_context(|| {
-                format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
-            })?;
+            .with_context(|| ks_err!("Failed to insert {:?}", p))?;
         }
         Ok(())
     }
@@ -1734,7 +1731,7 @@
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             metadata.store_in_db(key_id.0, tx).no_gc()
         })
-        .context("In insert_key_metadata.")
+        .context(ks_err!())
     }
 
     /// Stores a signed certificate chain signed by a remote provisioning server, keyed
@@ -1807,7 +1804,7 @@
                 .context("Failed to insert cert")?;
             Ok(()).no_gc()
         })
-        .context("In store_signed_attestation_certificate_chain: ")
+        .context(ks_err!())
     }
 
     /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
@@ -1823,13 +1820,8 @@
         match domain {
             Domain::APP | Domain::SELINUX => {}
             _ => {
-                return Err(KsError::sys()).context(format!(
-                    concat!(
-                        "In assign_attestation_key: Domain {:?} ",
-                        "must be either App or SELinux.",
-                    ),
-                    domain
-                ));
+                return Err(KsError::sys())
+                    .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
             }
         }
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
@@ -1874,7 +1866,7 @@
             }
             Ok(()).no_gc()
         })
-        .context("In assign_attestation_key: ")
+        .context(ks_err!())
     }
 
     /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
@@ -1918,7 +1910,7 @@
                 .context("Failed to execute statement")?;
             Ok(rows).no_gc()
         })
-        .context("In fetch_unsigned_attestation_keys")
+        .context(ks_err!())
     }
 
     /// Removes any keys that have expired as of the current time. Returns the number of keys
@@ -1958,7 +1950,7 @@
             }
             Ok(num_deleted).do_gc(num_deleted != 0)
         })
-        .context("In delete_expired_attestation_keys: ")
+        .context(ks_err!())
     }
 
     /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
@@ -1987,7 +1979,7 @@
                 .count() as i64;
             Ok(num_deleted).do_gc(num_deleted != 0)
         })
-        .context("In delete_all_attestation_keys: ")
+        .context(ks_err!())
     }
 
     /// Counts the number of keys that will expire by the provided epoch date and the number of
@@ -2054,7 +2046,7 @@
             }
             Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
         })
-        .context("In get_attestation_pool_status: ")
+        .context(ks_err!())
     }
 
     fn query_kid_for_attestation_key_and_cert_chain(
@@ -2111,24 +2103,24 @@
             }
         }
 
-        self.delete_expired_attestation_keys().context(
-            "In retrieve_attestation_key_and_cert_chain: failed to prune expired attestation keys",
-        )?;
-        let tx = self.conn.unchecked_transaction().context(
-            "In retrieve_attestation_key_and_cert_chain: Failed to initialize transaction.",
-        )?;
+        self.delete_expired_attestation_keys()
+            .context(ks_err!("Failed to prune expired attestation keys",))?;
+        let tx = self
+            .conn
+            .unchecked_transaction()
+            .context(ks_err!("Failed to initialize transaction."))?;
         let key_id: i64 = match self
             .query_kid_for_attestation_key_and_cert_chain(&tx, domain, namespace, km_uuid)?
         {
             None => return Ok(None),
             Some(kid) => kid,
         };
-        tx.commit()
-            .context("In retrieve_attestation_key_and_cert_chain: Failed to commit keyid query")?;
+        tx.commit().context(ks_err!("Failed to commit keyid query"))?;
         let key_id_guard = KEY_ID_LOCK.get(key_id);
-        let tx = self.conn.unchecked_transaction().context(
-            "In retrieve_attestation_key_and_cert_chain: Failed to initialize transaction.",
-        )?;
+        let tx = self
+            .conn
+            .unchecked_transaction()
+            .context(ks_err!("Failed to initialize transaction."))?;
         let mut stmt = tx.prepare(
             "SELECT subcomponent_type, blob
             FROM persistent.blobentry
@@ -2193,10 +2185,8 @@
         match *domain {
             Domain::APP | Domain::SELINUX => {}
             _ => {
-                return Err(KsError::sys()).context(format!(
-                    "In rebind_alias: Domain {:?} must be either App or SELinux.",
-                    domain
-                ));
+                return Err(KsError::sys())
+                    .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
             }
         }
         let updated = tx
@@ -2206,7 +2196,7 @@
                  WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
                 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
             )
-            .context("In rebind_alias: Failed to rebind existing entry.")?;
+            .context(ks_err!("Failed to rebind existing entry."))?;
         let result = tx
             .execute(
                 "UPDATE persistent.keyentry
@@ -2222,10 +2212,10 @@
                     key_type,
                 ],
             )
-            .context("In rebind_alias: Failed to set alias.")?;
+            .context(ks_err!("Failed to set alias."))?;
         if result != 1 {
-            return Err(KsError::sys()).context(format!(
-                "In rebind_alias: Expected to update a single entry but instead updated {}.",
+            return Err(KsError::sys()).context(ks_err!(
+                "Expected to update a single entry but instead updated {}.",
                 result
             ));
         }
@@ -2253,14 +2243,13 @@
         };
 
         // Security critical: Must return immediately on failure. Do not remove the '?';
-        check_permission(&destination)
-            .context("In migrate_key_namespace: Trying to check permission.")?;
+        check_permission(&destination).context(ks_err!("Trying to check permission."))?;
 
         let alias = destination
             .alias
             .as_ref()
             .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
-            .context("In migrate_key_namespace: Alias must be specified.")?;
+            .context(ks_err!("Alias must be specified."))?;
 
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             // Query the destination location. If there is a key, the migration request fails.
@@ -2294,7 +2283,7 @@
             }
             Ok(()).no_gc()
         })
-        .context("In migrate_key_namespace:")
+        .context(ks_err!())
     }
 
     /// Store a new key in a single transaction.
@@ -2322,7 +2311,7 @@
             }
             _ => {
                 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
-                    .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
+                    .context(ks_err!("Need alias and domain must be APP or SELINUX."));
             }
         };
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
@@ -2379,7 +2368,7 @@
                 || need_gc;
             Ok(key_id).do_gc(need_gc)
         })
-        .context("In store_new_key.")
+        .context(ks_err!())
     }
 
     /// Store a new certificate
@@ -2400,9 +2389,8 @@
                 (alias, key.domain, nspace)
             }
             _ => {
-                return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                    "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
-                )
+                return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
+                    .context(ks_err!("Need alias and domain must be APP or SELINUX."));
             }
         };
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
@@ -2429,7 +2417,7 @@
                 .context("Trying to rebind alias.")?;
             Ok(key_id).do_gc(need_gc)
         })
-        .context("In store_new_certificate.")
+        .context(ks_err!())
     }
 
     // Helper function loading the key_id given the key descriptor
@@ -2460,7 +2448,7 @@
                 .get(0)
                 .context("Failed to unpack id.")
         })
-        .context("In load_key_entry_id.")
+        .context(ks_err!())
     }
 
     /// This helper function completes the access tuple of a key, which is required
@@ -2595,10 +2583,9 @@
                 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
                     WHERE keyentryid = ? GROUP BY subcomponent_type;",
             )
-            .context("In load_blob_components: prepare statement failed.")?;
+            .context(ks_err!("prepare statement failed."))?;
 
-        let mut rows =
-            stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
+        let mut rows = stmt.query(params![key_id]).context(ks_err!("query failed."))?;
 
         let mut key_blob: Option<(i64, Vec<u8>)> = None;
         let mut cert_blob: Option<Vec<u8>> = None;
@@ -2630,13 +2617,13 @@
             }
             Ok(())
         })
-        .context("In load_blob_components.")?;
+        .context(ks_err!())?;
 
         let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
             Ok(Some((
                 blob,
                 BlobMetaData::load_from_db(blob_id, tx)
-                    .context("In load_blob_components: Trying to load blob_metadata.")?,
+                    .context(ks_err!("Trying to load blob_metadata."))?,
             )))
         })?;
 
@@ -2664,7 +2651,7 @@
             );
             Ok(())
         })
-        .context("In load_key_parameters.")?;
+        .context(ks_err!())?;
 
         Ok(parameters)
     }
@@ -2706,7 +2693,7 @@
                 _ => Ok(()).no_gc(),
             }
         })
-        .context("In check_and_update_key_usage_count.")
+        .context(ks_err!())
     }
 
     /// Load a key entry by the given key descriptor.
@@ -2738,7 +2725,7 @@
                         std::thread::sleep(std::time::Duration::from_micros(500));
                         continue;
                     } else {
-                        return Err(e).context("In load_key_entry.");
+                        return Err(e).context(ks_err!());
                     }
                 }
             }
@@ -2764,16 +2751,15 @@
         let tx = self
             .conn
             .unchecked_transaction()
-            .context("In load_key_entry: Failed to initialize transaction.")?;
+            .context(ks_err!("Failed to initialize transaction."))?;
 
         // Load the key_id and complete the access control tuple.
         let (key_id, access_key_descriptor, access_vector) =
-            Self::load_access_tuple(&tx, key, key_type, caller_uid)
-                .context("In load_key_entry.")?;
+            Self::load_access_tuple(&tx, key, key_type, caller_uid).context(ks_err!())?;
 
         // Perform access control. It is vital that we return here if the permission is denied.
         // So do not touch that '?' at the end.
-        check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
+        check_permission(&access_key_descriptor, access_vector).context(ks_err!())?;
 
         // KEY ID LOCK 2/2
         // If we did not get a key id lock by now, it was because we got a key descriptor
@@ -2790,7 +2776,7 @@
             None => match KEY_ID_LOCK.try_get(key_id) {
                 None => {
                     // Roll back the transaction.
-                    tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
+                    tx.rollback().context(ks_err!("Failed to roll back transaction."))?;
 
                     // Block until we have a key id lock.
                     let key_id_guard = KEY_ID_LOCK.get(key_id);
@@ -2799,7 +2785,7 @@
                     let tx = self
                         .conn
                         .unchecked_transaction()
-                        .context("In load_key_entry: Failed to initialize transaction.")?;
+                        .context(ks_err!("Failed to initialize transaction."))?;
 
                     Self::load_access_tuple(
                         &tx,
@@ -2813,7 +2799,7 @@
                         key_type,
                         caller_uid,
                     )
-                    .context("In load_key_entry. (deferred key lock)")?;
+                    .context(ks_err!("(deferred key lock)"))?;
                     (key_id_guard, tx)
                 }
                 Some(l) => (l, tx),
@@ -2821,10 +2807,10 @@
             Some(key_id_guard) => (key_id_guard, tx),
         };
 
-        let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
-            .context("In load_key_entry.")?;
+        let key_entry =
+            Self::load_key_components(&tx, load_bits, key_id_guard.id()).context(ks_err!())?;
 
-        tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
+        tx.commit().context(ks_err!("Failed to commit transaction."))?;
 
         Ok((key_id_guard, key_entry))
     }
@@ -2867,7 +2853,7 @@
                 .map(|need_gc| (need_gc, ()))
                 .context("Trying to mark the key unreferenced.")
         })
-        .context("In unbind_key.")
+        .context(ks_err!())
     }
 
     fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
@@ -2876,7 +2862,7 @@
             params![key_id],
             |row| row.get(0),
         )
-        .context("In get_key_km_uuid.")
+        .context(ks_err!())
     }
 
     /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
@@ -2885,8 +2871,7 @@
         let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_namespace", 500);
 
         if !(domain == Domain::APP || domain == Domain::SELINUX) {
-            return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
-                .context("In unbind_keys_for_namespace.");
+            return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!());
         }
         self.with_transaction(TransactionBehavior::Immediate, |tx| {
             tx.execute(
@@ -2924,7 +2909,7 @@
             .context("Trying to delete keyentry.")?;
             Ok(()).need_gc()
         })
-        .context("In unbind_keys_for_namespace")
+        .context(ks_err!())
     }
 
     fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
@@ -2965,7 +2950,7 @@
             .context("Trying to delete keyentry.")?;
             Result::<()>::Ok(())
         }
-        .context("In cleanup_unreferenced")
+        .context(ks_err!())
     }
 
     /// Delete the keys created on behalf of the user, denoted by the user id.
@@ -3012,7 +2997,7 @@
                     user_id,
                     KeyLifeCycle::Live
                 ])
-                .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
+                .context(ks_err!("Failed to query the keys created by apps."))?;
 
             let mut key_ids: Vec<i64> = Vec::new();
             db_utils::with_rows_extract_all(&mut rows, |row| {
@@ -3020,7 +3005,7 @@
                     .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
                 Ok(())
             })
-            .context("In unbind_keys_for_user.")?;
+            .context(ks_err!())?;
 
             let mut notify_gc = false;
             for key_id in key_ids {
@@ -3028,7 +3013,7 @@
                     // Load metadata and filter out non-super-encrypted keys.
                     if let (_, Some((_, blob_metadata)), _, _) =
                         Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
-                            .context("In unbind_keys_for_user: Trying to load blob info.")?
+                            .context(ks_err!("Trying to load blob info."))?
                     {
                         if blob_metadata.encrypted_by().is_none() {
                             continue;
@@ -3041,7 +3026,7 @@
             }
             Ok(()).do_gc(notify_gc)
         })
-        .context("In unbind_keys_for_user.")
+        .context(ks_err!())
     }
 
     fn load_key_components(
@@ -3093,11 +3078,11 @@
                      AND state = ?
                      AND key_type = ?;",
                 )
-                .context("In list: Failed to prepare.")?;
+                .context(ks_err!("Failed to prepare."))?;
 
             let mut rows = stmt
                 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type])
-                .context("In list: Failed to query.")?;
+                .context(ks_err!("Failed to query."))?;
 
             let mut descriptors: Vec<KeyDescriptor> = Vec::new();
             db_utils::with_rows_extract_all(&mut rows, |row| {
@@ -3109,7 +3094,7 @@
                 });
                 Ok(())
             })
-            .context("In list: Failed to extract rows.")?;
+            .context(ks_err!("Failed to extract rows."))?;
             Ok(descriptors).no_gc()
         })
     }
@@ -3141,8 +3126,7 @@
             // But even if we load the access tuple by grant here, the permission
             // check denies the attempt to create a grant by grant descriptor.
             let (key_id, access_key_descriptor, _) =
-                Self::load_access_tuple(tx, key, KeyType::Client, caller_uid)
-                    .context("In grant")?;
+                Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
 
             // Perform access control. It is vital that we return here if the permission
             // was denied. So do not touch that '?' at the end of the line.
@@ -3150,7 +3134,7 @@
             // for the given key and in addition to all of the permissions
             // expressed in `access_vector`.
             check_permission(&access_key_descriptor, &access_vector)
-                .context("In grant: check_permission failed.")?;
+                .context(ks_err!("check_permission failed"))?;
 
             let grant_id = if let Some(grant_id) = tx
                 .query_row(
@@ -3160,7 +3144,7 @@
                     |row| row.get(0),
                 )
                 .optional()
-                .context("In grant: Failed get optional existing grant id.")?
+                .context(ks_err!("Failed get optional existing grant id."))?
             {
                 tx.execute(
                     "UPDATE persistent.grant
@@ -3168,7 +3152,7 @@
                     WHERE id = ?;",
                     params![i32::from(access_vector), grant_id],
                 )
-                .context("In grant: Failed to update existing grant.")?;
+                .context(ks_err!("Failed to update existing grant."))?;
                 grant_id
             } else {
                 Self::insert_with_retry(|id| {
@@ -3178,7 +3162,7 @@
                         params![id, grantee_uid, key_id, i32::from(access_vector)],
                     )
                 })
-                .context("In grant")?
+                .context(ks_err!())?
             };
 
             Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
@@ -3201,13 +3185,12 @@
             // Load the key_id and complete the access control tuple.
             // We ignore the access vector here because grants cannot be granted.
             let (key_id, access_key_descriptor, _) =
-                Self::load_access_tuple(tx, key, KeyType::Client, caller_uid)
-                    .context("In ungrant.")?;
+                Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
 
             // Perform access control. We must return here if the permission
             // was denied. So do not touch the '?' at the end of this line.
             check_permission(&access_key_descriptor)
-                .context("In grant: check_permission failed.")?;
+                .context(ks_err!("check_permission failed."))?;
 
             tx.execute(
                 "DELETE FROM persistent.grant
@@ -3239,7 +3222,7 @@
                     _,
                 )) => (),
                 Err(e) => {
-                    return Err(e).context("In insert_with_retry: failed to insert into database.")
+                    return Err(e).context(ks_err!("failed to insert into database."));
                 }
                 _ => return Ok(newid),
             }
@@ -3298,7 +3281,7 @@
             .context("Trying to load key descriptor")
             .no_gc()
         })
-        .context("In load_key_descriptor.")
+        .context(ks_err!())
     }
 }
 
@@ -3366,7 +3349,7 @@
         db.with_transaction(TransactionBehavior::Immediate, |tx| {
             KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace, KeyType::Client).no_gc()
         })
-        .context("In rebind_alias.")
+        .context(ks_err!())
     }
 
     #[test]
@@ -3518,15 +3501,15 @@
         // Test that we must pass in a valid Domain.
         check_result_is_error_containing_string(
             db.create_key_entry(&Domain::GRANT, &102, KeyType::Client, &KEYSTORE_UUID),
-            "Domain Domain(1) must be either App or SELinux.",
+            &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
         );
         check_result_is_error_containing_string(
             db.create_key_entry(&Domain::BLOB, &103, KeyType::Client, &KEYSTORE_UUID),
-            "Domain Domain(3) must be either App or SELinux.",
+            &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
         );
         check_result_is_error_containing_string(
             db.create_key_entry(&Domain::KEY_ID, &104, KeyType::Client, &KEYSTORE_UUID),
-            "Domain Domain(4) must be either App or SELinux.",
+            &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
         );
 
         Ok(())
@@ -3825,15 +3808,15 @@
         // Test that we must pass in a valid Domain.
         check_result_is_error_containing_string(
             rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
-            "Domain Domain(1) must be either App or SELinux.",
+            &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
         );
         check_result_is_error_containing_string(
             rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
-            "Domain Domain(3) must be either App or SELinux.",
+            &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
         );
         check_result_is_error_containing_string(
             rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
-            "Domain Domain(4) must be either App or SELinux.",
+            &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
         );
 
         // Test that we correctly handle setting an alias for something that does not exist.
@@ -5039,8 +5022,8 @@
         let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
             .iter()
             .map(|(domain, ns, alias)| {
-                let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
-                    .unwrap_or_else(|e| {
+                let entry =
+                    make_test_key_entry(&mut db, *domain, *ns, alias, None).unwrap_or_else(|e| {
                         panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
                     });
                 (entry.id(), *ns)
diff --git a/keystore2/src/ec_crypto.rs b/keystore2/src/ec_crypto.rs
index 0425d4a..4fb3747 100644
--- a/keystore2/src/ec_crypto.rs
+++ b/keystore2/src/ec_crypto.rs
@@ -14,6 +14,7 @@
 
 //! Implement ECDH-based encryption.
 
+use crate::ks_err;
 use anyhow::{Context, Result};
 use keystore2_crypto::{
     aes_gcm_decrypt, aes_gcm_encrypt, ec_key_generate_key, ec_key_get0_public_key,
@@ -28,29 +29,23 @@
 impl ECDHPrivateKey {
     /// Randomly generate a fresh keypair.
     pub fn generate() -> Result<ECDHPrivateKey> {
-        ec_key_generate_key()
-            .map(ECDHPrivateKey)
-            .context("In ECDHPrivateKey::generate: generation failed")
+        ec_key_generate_key().map(ECDHPrivateKey).context(ks_err!("generation failed"))
     }
 
     /// Deserialize bytes into an ECDH keypair
     pub fn from_private_key(buf: &[u8]) -> Result<ECDHPrivateKey> {
-        ec_key_parse_private_key(buf)
-            .map(ECDHPrivateKey)
-            .context("In ECDHPrivateKey::from_private_key: parsing failed")
+        ec_key_parse_private_key(buf).map(ECDHPrivateKey).context(ks_err!("parsing failed"))
     }
 
     /// Serialize the ECDH key into bytes
     pub fn private_key(&self) -> Result<ZVec> {
-        ec_key_marshal_private_key(&self.0)
-            .context("In ECDHPrivateKey::private_key: marshalling failed")
+        ec_key_marshal_private_key(&self.0).context(ks_err!("marshalling failed"))
     }
 
     /// Generate the serialization of the corresponding public key
     pub fn public_key(&self) -> Result<Vec<u8>> {
         let point = ec_key_get0_public_key(&self.0);
-        ec_point_point_to_oct(point.get_point())
-            .context("In ECDHPrivateKey::public_key: marshalling failed")
+        ec_point_point_to_oct(point.get_point()).context(ks_err!("marshalling failed"))
     }
 
     /// Use ECDH to agree an AES key with another party whose public key we have.
@@ -64,18 +59,17 @@
         recipient_public_key: &[u8],
     ) -> Result<ZVec> {
         let hkdf = hkdf_extract(sender_public_key, salt)
-            .context("In ECDHPrivateKey::agree_key: hkdf_extract on sender_public_key failed")?;
+            .context(ks_err!("hkdf_extract on sender_public_key failed"))?;
         let hkdf = hkdf_extract(recipient_public_key, &hkdf)
-            .context("In ECDHPrivateKey::agree_key: hkdf_extract on recipient_public_key failed")?;
+            .context(ks_err!("hkdf_extract on recipient_public_key failed"))?;
         let other_public_key = ec_point_oct_to_point(other_public_key)
-            .context("In ECDHPrivateKey::agree_key: ec_point_oct_to_point failed")?;
+            .context(ks_err!("ec_point_oct_to_point failed"))?;
         let secret = ecdh_compute_key(other_public_key.get_point(), &self.0)
-            .context("In ECDHPrivateKey::agree_key: ecdh_compute_key failed")?;
-        let prk = hkdf_extract(&secret, &hkdf)
-            .context("In ECDHPrivateKey::agree_key: hkdf_extract on secret failed")?;
+            .context(ks_err!("ecdh_compute_key failed"))?;
+        let prk = hkdf_extract(&secret, &hkdf).context(ks_err!("hkdf_extract on secret failed"))?;
 
         let aes_key = hkdf_expand(AES_256_KEY_LENGTH, &prk, b"AES-256-GCM key")
-            .context("In ECDHPrivateKey::agree_key: hkdf_expand failed")?;
+            .context(ks_err!("hkdf_expand failed"))?;
         Ok(aes_key)
     }
 
@@ -84,18 +78,14 @@
         recipient_public_key: &[u8],
         message: &[u8],
     ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)> {
-        let sender_key =
-            Self::generate().context("In ECDHPrivateKey::encrypt_message: generate failed")?;
-        let sender_public_key = sender_key
-            .public_key()
-            .context("In ECDHPrivateKey::encrypt_message: public_key failed")?;
-        let salt =
-            generate_salt().context("In ECDHPrivateKey::encrypt_message: generate_salt failed")?;
+        let sender_key = Self::generate().context(ks_err!("generate failed"))?;
+        let sender_public_key = sender_key.public_key().context(ks_err!("public_key failed"))?;
+        let salt = generate_salt().context(ks_err!("generate_salt failed"))?;
         let aes_key = sender_key
             .agree_key(&salt, recipient_public_key, &sender_public_key, recipient_public_key)
-            .context("In ECDHPrivateKey::encrypt_message: agree_key failed")?;
-        let (ciphertext, iv, tag) = aes_gcm_encrypt(message, &aes_key)
-            .context("In ECDHPrivateKey::encrypt_message: aes_gcm_encrypt failed")?;
+            .context(ks_err!("agree_key failed"))?;
+        let (ciphertext, iv, tag) =
+            aes_gcm_encrypt(message, &aes_key).context(ks_err!("aes_gcm_encrypt failed"))?;
         Ok((sender_public_key, salt, iv, ciphertext, tag))
     }
 
@@ -111,9 +101,8 @@
         let recipient_public_key = self.public_key()?;
         let aes_key = self
             .agree_key(salt, sender_public_key, sender_public_key, &recipient_public_key)
-            .context("In ECDHPrivateKey::decrypt_message: agree_key failed")?;
-        aes_gcm_decrypt(ciphertext, iv, tag, &aes_key)
-            .context("In ECDHPrivateKey::decrypt_message: aes_gcm_decrypt failed")
+            .context(ks_err!("agree_key failed"))?;
+        aes_gcm_decrypt(ciphertext, iv, tag, &aes_key).context(ks_err!("aes_gcm_decrypt failed"))
     }
 }
 
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index cb6a266..8d5e985 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -14,6 +14,7 @@
 
 //! This is the Keystore 2.0 Enforcements module.
 // TODO: more description to follow.
+use crate::ks_err;
 use crate::error::{map_binder_status, Error, ErrorCode};
 use crate::globals::{get_timestamp_service, ASYNC_TASK, DB, ENFORCEMENTS};
 use crate::key_parameter::{KeyParameter, KeyParameterValue};
@@ -95,14 +96,14 @@
             .unwrap()
             .take()
             .ok_or(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
-            .context("In get_auth_tokens: No operation auth token received.")?;
+            .context(ks_err!("No operation auth token received."))?;
 
         let tst = match &self.state {
             AuthRequestState::TimeStampedOpAuth(recv) | AuthRequestState::TimeStamp(recv) => {
                 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
-                Some(result.context(concat!(
-                    "In get_auth_tokens: Worker responded with error ",
-                    "from generating timestamp token."
+                Some(result.context(ks_err!(
+                    "Worker responded with error \
+                    from generating timestamp token.",
                 ))?)
             }
             AuthRequestState::OpAuth => None,
@@ -228,10 +229,7 @@
 fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
     if let Err(e) = sender.send(get_timestamp_token(challenge)) {
         log::info!(
-            concat!(
-                "In timestamp_token_request: Receiver hung up ",
-                "before timestamp token could be delivered. {:?}"
-            ),
+            concat!("Receiver hung up ", "before timestamp token could be delivered. {:?}"),
             e
         );
     }
@@ -322,7 +320,7 @@
                     .check_and_update_key_usage_count(key_id)
                     .context("Trying to update key usage count.")
             })
-            .context("In after_finish.")?;
+            .context(ks_err!())?;
         }
         Ok(())
     }
@@ -349,14 +347,14 @@
             DeferredAuthState::OpAuthRequired
             | DeferredAuthState::TimeStampedOpAuthRequired
             | DeferredAuthState::TimeStampRequired(_) => {
-                Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(concat!(
-                    "In AuthInfo::get_auth_tokens: No operation auth token requested??? ",
-                    "This should not happen."
+                Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(ks_err!(
+                    "No operation auth token requested??? \
+                    This should not happen."
                 ))
             }
             // This should not be reachable, because it should have been handled above.
             DeferredAuthState::Waiting(_) => {
-                Err(Error::sys()).context("In AuthInfo::get_auth_tokens: Cannot be reached.")
+                Err(Error::sys()).context(ks_err!("AuthInfo::get_auth_tokens: Cannot be reached.",))
             }
         }
     }
@@ -418,7 +416,7 @@
                         key_usage_limited: None,
                         confirmation_token_receiver: None,
                     },
-                ))
+                ));
             }
         };
 
@@ -428,7 +426,7 @@
             // Rule out WRAP_KEY purpose
             KeyPurpose::WRAP_KEY => {
                 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
-                    .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
+                    .context(ks_err!("WRAP_KEY purpose is not allowed here.",));
             }
             // Allow AGREE_KEY for EC keys only.
             KeyPurpose::AGREE_KEY => {
@@ -436,9 +434,8 @@
                     if kp.get_tag() == Tag::ALGORITHM
                         && *kp.key_parameter_value() != KeyParameterValue::Algorithm(Algorithm::EC)
                     {
-                        return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
-                            "In authorize_create: key agreement is only supported for EC keys.",
-                        );
+                        return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
+                            .context(ks_err!("key agreement is only supported for EC keys.",));
                     }
                 }
             }
@@ -449,10 +446,10 @@
                     match *kp.key_parameter_value() {
                         KeyParameterValue::Algorithm(Algorithm::RSA)
                         | KeyParameterValue::Algorithm(Algorithm::EC) => {
-                            return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
-                                "In authorize_create: public operations on asymmetric keys are not \
-                                 supported.",
-                            );
+                            return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(ks_err!(
+                                "public operations on asymmetric keys are \
+                                 not supported."
+                            ));
                         }
                         _ => {}
                     }
@@ -460,7 +457,7 @@
             }
             _ => {
                 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
-                    .context("In authorize_create: specified purpose is not supported.");
+                    .context(ks_err!("authorize_create: specified purpose is not supported."));
             }
         }
         // The following variables are to record information from key parameters to be used in
@@ -505,23 +502,21 @@
                 KeyParameterValue::ActiveDateTime(a) => {
                     if !Enforcements::is_given_time_passed(*a, true) {
                         return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
-                            .context("In authorize_create: key is not yet active.");
+                            .context(ks_err!("key is not yet active."));
                     }
                 }
                 KeyParameterValue::OriginationExpireDateTime(o) => {
                     if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
                         && Enforcements::is_given_time_passed(*o, false)
                     {
-                        return Err(Error::Km(Ec::KEY_EXPIRED))
-                            .context("In authorize_create: key is expired.");
+                        return Err(Error::Km(Ec::KEY_EXPIRED)).context(ks_err!("key is expired."));
                     }
                 }
                 KeyParameterValue::UsageExpireDateTime(u) => {
                     if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
                         && Enforcements::is_given_time_passed(*u, false)
                     {
-                        return Err(Error::Km(Ec::KEY_EXPIRED))
-                            .context("In authorize_create: key is expired.");
+                        return Err(Error::Km(Ec::KEY_EXPIRED)).context(ks_err!("key is expired."));
                     }
                 }
                 KeyParameterValue::UserSecureID(s) => {
@@ -560,24 +555,23 @@
         // authorize the purpose
         if !key_purpose_authorized {
             return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
-                .context("In authorize_create: the purpose is not authorized.");
+                .context(ks_err!("the purpose is not authorized."));
         }
 
         // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
         if !user_secure_ids.is_empty() && no_auth_required {
-            return Err(Error::Km(Ec::INVALID_KEY_BLOB)).context(
-                "In authorize_create: key has both NO_AUTH_REQUIRED and USER_SECURE_ID tags.",
-            );
+            return Err(Error::Km(Ec::INVALID_KEY_BLOB))
+                .context(ks_err!("key has both NO_AUTH_REQUIRED and USER_SECURE_ID tags."));
         }
 
         // if either of auth_type or secure_id is present and the other is not present, return error
         if (user_auth_type.is_some() && user_secure_ids.is_empty())
             || (user_auth_type.is_none() && !user_secure_ids.is_empty())
         {
-            return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
-                "In authorize_create: Auth required, but either auth type or secure ids \
-                 are not present.",
-            );
+            return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(ks_err!(
+                "Auth required, but either auth type or secure ids \
+                 are not present."
+            ));
         }
 
         // validate caller nonce for origination purposes
@@ -585,24 +579,22 @@
             && !caller_nonce_allowed
             && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
         {
-            return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
-                "In authorize_create, NONCE is present, although CALLER_NONCE is not present",
-            );
+            return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED))
+                .context(ks_err!("NONCE is present, although CALLER_NONCE is not present"));
         }
 
         if unlocked_device_required {
             // check the device locked status. If locked, operations on the key are not
             // allowed.
             if self.is_device_locked(user_id) {
-                return Err(Error::Km(Ec::DEVICE_LOCKED))
-                    .context("In authorize_create: device is locked.");
+                return Err(Error::Km(Ec::DEVICE_LOCKED)).context(ks_err!("device is locked."));
             }
         }
 
         if let Some(level) = max_boot_level {
             if !SUPER_KEY.read().unwrap().level_accessible(level) {
                 return Err(Error::Km(Ec::BOOT_LEVEL_EXCEEDED))
-                    .context("In authorize_create: boot level is too late.");
+                    .context(ks_err!("boot level is too late."));
             }
         }
 
@@ -636,7 +628,7 @@
             Some(
                 hat_and_last_off_body
                     .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
-                    .context("In authorize_create: No suitable auth token found.")?,
+                    .context(ks_err!("No suitable auth token found."))?,
             )
         } else {
             None
@@ -649,16 +641,16 @@
                 let token_age = now
                     .checked_sub(&hat.time_received())
                     .ok_or_else(Error::sys)
-                    .context(concat!(
-                        "In authorize_create: Overflow while computing Auth token validity. ",
-                        "Validity cannot be established."
+                    .context(ks_err!(
+                        "Overflow while computing Auth token validity. \
+                    Validity cannot be established."
                     ))?;
 
                 let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
 
                 if token_age.seconds() > key_time_out && !on_body_extended {
                     return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
-                        .context("In authorize_create: matching auth token is expired.");
+                        .context(ks_err!("matching auth token is expired."));
                 }
                 Some(hat)
             }
@@ -832,20 +824,20 @@
                     auth_token_entry.take_auth_token()
                 } else {
                     return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND))
-                        .context("In get_auth_tokens: No auth token found.");
+                        .context(ks_err!("No auth token found."));
                 }
             } else {
                 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND)).context(
-                    concat!(
-                        "In get_auth_tokens: No auth token found for ",
-                        "the given challenge and passed-in auth token max age is zero."
+                    ks_err!(
+                        "No auth token found for \
+                    the given challenge and passed-in auth token max age is zero."
                     ),
                 );
             }
         };
         // Wait and obtain the timestamp token from secure clock service.
-        let tst = get_timestamp_token(challenge)
-            .context("In get_auth_tokens. Error in getting timestamp token.")?;
+        let tst =
+            get_timestamp_token(challenge).context(ks_err!("Error in getting timestamp token."))?;
         Ok((auth_token, tst))
     }
 }
diff --git a/keystore2/src/gc.rs b/keystore2/src/gc.rs
index 341aa0a..a033356 100644
--- a/keystore2/src/gc.rs
+++ b/keystore2/src/gc.rs
@@ -18,6 +18,7 @@
 //! optionally dispose of sensitive key material appropriately, and then delete
 //! the key entry from the database.
 
+use crate::ks_err;
 use crate::{
     async_task,
     database::{BlobMetaData, KeystoreDB, Uuid},
@@ -103,7 +104,7 @@
             let blobs = self
                 .db
                 .handle_next_superseded_blobs(&self.deleted_blob_ids, 20)
-                .context("In process_one_key: Trying to handle superseded blob.")?;
+                .context(ks_err!("Trying to handle superseded blob."))?;
             self.deleted_blob_ids = vec![];
             self.superseded_blobs = blobs;
         }
@@ -124,9 +125,8 @@
                     .read()
                     .unwrap()
                     .unwrap_key_if_required(&blob_metadata, &blob)
-                    .context("In process_one_key: Trying to unwrap to-be-deleted blob.")?;
-                (self.invalidate_key)(uuid, &*blob)
-                    .context("In process_one_key: Trying to invalidate key.")?;
+                    .context(ks_err!("Trying to unwrap to-be-deleted blob.",))?;
+                (self.invalidate_key)(uuid, &blob).context(ks_err!("Trying to invalidate key."))?;
             }
         }
         Ok(())
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index edbe6ce..425812f 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -16,6 +16,7 @@
 //! database connections and connections to services that Keystore needs
 //! to talk to.
 
+use crate::ks_err;
 use crate::gc::Gc;
 use crate::legacy_blob::LegacyBlobLoader;
 use crate::legacy_importer::LegacyImporter;
@@ -30,9 +31,10 @@
 use crate::km_compat::{KeyMintV1, BacklevelKeyMintWrapper};
 use crate::{enforcements::Enforcements, error::map_km_error};
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-    IKeyMintDevice::IKeyMintDevice, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
-    KeyMintHardwareInfo::KeyMintHardwareInfo, SecurityLevel::SecurityLevel,
+    IKeyMintDevice::IKeyMintDevice, KeyMintHardwareInfo::KeyMintHardwareInfo,
+    SecurityLevel::SecurityLevel,
 };
+use android_hardware_security_rkp::aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent::IRemotelyProvisionedComponent;
 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
     ISecureClock::ISecureClock,
 };
@@ -187,7 +189,7 @@
                 let km_dev = get_keymint_dev_by_uuid(uuid).map(|(dev, _)| dev)?;
                 let _wp = wd::watch_millis("In invalidate key closure: calling deleteKey", 500);
                 map_km_error(km_dev.deleteKey(blob))
-                    .context("In invalidate key closure: Trying to invalidate key blob.")
+                    .context(ks_err!("Trying to invalidate key blob."))
             }),
             KeystoreDB::new(&DB_PATH.read().expect("Could not get the database directory."), None)
                 .expect("Failed to open database."),
@@ -224,9 +226,10 @@
             }
         }
         _ => {
-            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(format!(
-                "In keymint_service_name_by_version: Trying to find keymint V{} for security level: {:?}",
-                version, security_level
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(ks_err!(
+                "Trying to find keymint V{} for security level: {:?}",
+                version,
+                security_level
             ));
         }
     };
@@ -251,12 +254,12 @@
                 Ok(sl)
             }
         })
-        .context("In connect_keymint.")?;
+        .context(ks_err!())?;
 
     let (keymint, hal_version) = if let Some((version, service_name)) = service_name {
         let km: Strong<dyn IKeyMintDevice> =
             map_binder_status_code(binder::get_interface(&service_name))
-                .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?;
+                .context(ks_err!("Trying to connect to genuine KeyMint service."))?;
         // Map the HAL version code for KeyMint to be <AIDL version> * 100, so
         // - V1 is 100
         // - V2 is 200
@@ -268,7 +271,7 @@
 
         let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
             map_binder_status_code(binder::get_interface("android.security.compat"))
-                .context("In connect_keymint: Trying to connect to compat service.")?;
+                .context(ks_err!("Trying to connect to compat service."))?;
         (
             map_binder_status(keystore_compat_service.getKeyMintDevice(*security_level))
                 .map_err(|e| match e {
@@ -277,7 +280,7 @@
                     }
                     e => e,
                 })
-                .context("In connect_keymint: Trying to get Legacy wrapper.")?,
+                .context(ks_err!("Trying to get Legacy wrapper."))?,
             None,
         )
     };
@@ -302,7 +305,7 @@
                 security_level
             );
             BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint)
-                .context("In connect_keymint: Trying to create V1 compatibility wrapper.")?
+                .context(ks_err!("Trying to create V1 compatibility wrapper."))?
         }
         None => {
             // Compatibility wrapper around a KeyMaster device: this roughly
@@ -312,21 +315,21 @@
                 "Add emulation wrapper around Keymaster device for security level: {:?}",
                 security_level
             );
-            BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint).context(
-                "In connect_keymint: Trying to create km_compat V1 compatibility wrapper .",
-            )?
+            BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint)
+                .context(ks_err!("Trying to create km_compat V1 compatibility wrapper ."))?
         }
         _ => {
-            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(format!(
-                "In connect_keymint: unexpected hal_version {:?} for security level: {:?}",
-                hal_version, security_level
-            ))
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(ks_err!(
+                "unexpected hal_version {:?} for security level: {:?}",
+                hal_version,
+                security_level
+            ));
         }
     };
 
     let wp = wd::watch_millis("In connect_keymint: calling getHardwareInfo()", 500);
-    let mut hw_info = map_km_error(keymint.getHardwareInfo())
-        .context("In connect_keymint: Failed to get hardware info.")?;
+    let mut hw_info =
+        map_km_error(keymint.getHardwareInfo()).context(ks_err!("Failed to get hardware info."))?;
     drop(wp);
 
     // The legacy wrapper sets hw_info.versionNumber to the underlying HAL version like so:
@@ -356,7 +359,7 @@
     if let Some((dev, hw_info, uuid)) = devices_map.dev_by_sec_level(security_level) {
         Ok((dev, hw_info, uuid))
     } else {
-        let (dev, hw_info) = connect_keymint(security_level).context("In get_keymint_device.")?;
+        let (dev, hw_info) = connect_keymint(security_level).context(ks_err!())?;
         devices_map.insert(*security_level, dev, hw_info);
         // Unwrap must succeed because we just inserted it.
         Ok(devices_map.dev_by_sec_level(security_level).unwrap())
@@ -374,7 +377,7 @@
     if let Some((dev, hw_info, _)) = devices_map.dev_by_uuid(uuid) {
         Ok((dev, hw_info))
     } else {
-        Err(Error::sys()).context("In get_keymint_dev_by_uuid: No KeyMint instance found.")
+        Err(Error::sys()).context(ks_err!("No KeyMint instance found."))
     }
 }
 
@@ -399,14 +402,14 @@
 
     let secureclock = if secure_clock_available {
         map_binder_status_code(binder::get_interface(&default_time_stamp_service_name))
-            .context("In connect_secureclock: Trying to connect to genuine secure clock service.")
+            .context(ks_err!("Trying to connect to genuine secure clock service."))
     } else {
         // This is a no-op if it was called before.
         keystore2_km_compat::add_keymint_device_service();
 
         let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
             map_binder_status_code(binder::get_interface("android.security.compat"))
-                .context("In connect_secureclock: Trying to connect to compat service.")?;
+                .context(ks_err!("Trying to connect to compat service."))?;
 
         // Legacy secure clock services were only implemented by TEE.
         map_binder_status(keystore_compat_service.getSecureClock())
@@ -416,7 +419,7 @@
                 }
                 e => e,
             })
-            .context("In connect_secureclock: Trying to get Legacy wrapper.")
+            .context(ks_err!("Trying to get Legacy wrapper."))
     }?;
 
     Ok(secureclock)
@@ -429,7 +432,7 @@
     if let Some(dev) = &*ts_device {
         Ok(dev.clone())
     } else {
-        let dev = connect_secureclock().context("In get_timestamp_service.")?;
+        let dev = connect_secureclock().context(ks_err!())?;
         *ts_device = Some(dev.clone());
         Ok(dev)
     }
@@ -462,13 +465,11 @@
         _ => None,
     }
     .ok_or(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
-    .context("In connect_remotely_provisioned_component.")?;
+    .context(ks_err!())?;
 
     let rem_prov_hal: Strong<dyn IRemotelyProvisionedComponent> =
-        map_binder_status_code(binder::get_interface(&service_name)).context(concat!(
-            "In connect_remotely_provisioned_component: Trying to connect to",
-            " RemotelyProvisionedComponent service."
-        ))?;
+        map_binder_status_code(binder::get_interface(&service_name))
+            .context(ks_err!("Trying to connect to RemotelyProvisionedComponent service."))?;
     Ok(rem_prov_hal)
 }
 
@@ -481,8 +482,7 @@
     if let Some(dev) = devices_map.dev_by_sec_level(security_level) {
         Ok(dev)
     } else {
-        let dev = connect_remotely_provisioned_component(security_level)
-            .context("In get_remotely_provisioned_component.")?;
+        let dev = connect_remotely_provisioned_component(security_level).context(ks_err!())?;
         devices_map.insert(*security_level, dev);
         // Unwrap must succeed because we just inserted it.
         Ok(devices_map.dev_by_sec_level(security_level).unwrap())
diff --git a/keystore2/src/id_rotation.rs b/keystore2/src/id_rotation.rs
index e3992d8..460caa7 100644
--- a/keystore2/src/id_rotation.rs
+++ b/keystore2/src/id_rotation.rs
@@ -20,6 +20,8 @@
 //! It is assumed that the timestamp file does not exist after a factory reset. So the creation
 //! time of the timestamp file provides a lower bound for the time since factory reset.
 
+use crate::ks_err;
+
 use anyhow::{Context, Result};
 use std::fs;
 use std::io::ErrorKind;
@@ -66,7 +68,7 @@
                 _ => Err(e).context("Failed to open timestamp file."),
             },
         }
-        .context("In had_factory_reset_since_id_rotation:")
+        .context(ks_err!())
     }
 }
 
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index 55f5d15..c54753c 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -47,7 +47,16 @@
         android_logger::Config::default()
             .with_tag("keystore2")
             .with_min_level(log::Level::Debug)
-            .with_log_id(android_logger::LogId::System),
+            .with_log_id(android_logger::LogId::System)
+            .format(|buf, record| {
+                writeln!(
+                    buf,
+                    "{}:{} - {}",
+                    record.file().unwrap_or("unknown"),
+                    record.line().unwrap_or(0),
+                    record.args()
+                )
+            }),
     );
     // Redirect panic messages to logcat.
     panic::set_hook(Box::new(|panic_info| {
diff --git a/keystore2/src/km_compat.rs b/keystore2/src/km_compat.rs
index 788beef..035edd9 100644
--- a/keystore2/src/km_compat.rs
+++ b/keystore2/src/km_compat.rs
@@ -15,6 +15,7 @@
 //! Provide a wrapper around a KeyMint device that allows up-level features to
 //! be emulated on back-level devices.
 
+use crate::ks_err;
 use crate::error::{map_binder_status, map_binder_status_code, map_or_log_err, Error, ErrorCode};
 use android_hardware_security_keymint::binder::{BinderFeatures, StatusCode, Strong};
 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::TimeStampToken::TimeStampToken;
@@ -81,7 +82,7 @@
     result.extend_from_slice(KEYBLOB_PREFIX);
     result.extend_from_slice(keyblob);
     let tag = hmac_sha256(KEYBLOB_HMAC_KEY, keyblob)
-        .context("In wrap_keyblob, failed to calculate HMAC-SHA256")?;
+        .context(ks_err!("failed to calculate HMAC-SHA256"))?;
     result.extend_from_slice(&tag);
     Ok(result)
 }
@@ -138,10 +139,9 @@
         // This is a no-op if it was called before.
         keystore2_km_compat::add_keymint_device_service();
 
-        let keystore_compat_service: Strong<dyn IKeystoreCompatService> = map_binder_status_code(
-            binder::get_interface("android.security.compat"),
-        )
-        .context("In BacklevelKeyMintWrapper::wrap: Trying to connect to compat service.")?;
+        let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
+            map_binder_status_code(binder::get_interface("android.security.compat"))
+                .context(ks_err!("Trying to connect to compat service."))?;
         let soft =
             map_binder_status(keystore_compat_service.getKeyMintDevice(SecurityLevel::SOFTWARE))
                 .map_err(|e| match e {
@@ -150,7 +150,7 @@
                     }
                     e => e,
                 })
-                .context("In BacklevelKeyMintWrapper::wrap: Trying to get software device.")?;
+                .context(ks_err!("Trying to get software device."))?;
 
         Ok(BnKeyMintDevice::new_binder(
             Self { real, soft, emu },
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index d513db0..e27cd1c 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -500,8 +500,30 @@
 ScopedAStatus KeyMintDevice::importKey(const std::vector<KeyParameter>& inKeyParams,
                                        KeyFormat in_inKeyFormat,
                                        const std::vector<uint8_t>& in_inKeyData,
-                                       const std::optional<AttestationKey>& /* in_attestationKey */,
+                                       const std::optional<AttestationKey>& in_attestationKey,
                                        KeyCreationResult* out_creationResult) {
+    // Since KeyMaster doesn't support ECDH, route all ECDH key import requests to
+    // soft-KeyMint.
+    //
+    // For this to work we'll need to also route begin() and deleteKey() calls to
+    // soft-KM. In order to do that, we'll prefix all keyblobs with whether it was
+    // created by the real underlying KeyMaster HAL or whether it was created by
+    // soft-KeyMint.
+    //
+    // See keyBlobPrefix() for more discussion.
+    //
+    for (const auto& keyParam : inKeyParams) {
+        if (keyParam.tag == Tag::PURPOSE &&
+            keyParam.value.get<KeyParameterValue::Tag::keyPurpose>() == KeyPurpose::AGREE_KEY) {
+            auto ret = softKeyMintDevice_->importKey(inKeyParams, in_inKeyFormat, in_inKeyData,
+                                                     in_attestationKey, out_creationResult);
+            if (ret.isOk()) {
+                out_creationResult->keyBlob = keyBlobPrefix(out_creationResult->keyBlob, true);
+            }
+            return ret;
+        }
+    }
+
     auto legacyKeyGENParams = convertKeyParametersToLegacy(extractGenerationParams(inKeyParams));
     auto legacyKeyFormat = convertKeyFormatToLegacy(in_inKeyFormat);
     KMV1::ErrorCode errorCode;
diff --git a/keystore2/src/km_compat/km_compat_type_conversion.h b/keystore2/src/km_compat/km_compat_type_conversion.h
index 33248a4..5db7e3d 100644
--- a/keystore2/src/km_compat/km_compat_type_conversion.h
+++ b/keystore2/src/km_compat/km_compat_type_conversion.h
@@ -750,6 +750,7 @@
     case KMV1::Tag::CERTIFICATE_SUBJECT:
     case KMV1::Tag::CERTIFICATE_NOT_BEFORE:
     case KMV1::Tag::CERTIFICATE_NOT_AFTER:
+    case KMV1::Tag::ATTESTATION_ID_SECOND_IMEI:
         // These tags do not exist in KM < KeyMint 1.0.
         break;
     case KMV1::Tag::MAX_BOOT_LEVEL:
diff --git a/keystore2/src/ks_err.rs b/keystore2/src/ks_err.rs
new file mode 100644
index 0000000..c9c38c0
--- /dev/null
+++ b/keystore2/src/ks_err.rs
@@ -0,0 +1,35 @@
+// Copyright 2020, 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.
+
+//! A ks_err macro that expands error messages to include the file and line number
+
+///
+/// # Examples
+///
+/// ```
+/// use crate::ks_err;
+///
+/// ks_err!("Key is expired.");
+/// Result:
+/// "src/lib.rs:7 Key is expired."
+/// ```
+#[macro_export]
+macro_rules! ks_err {
+    { $($arg:tt)+ } => {
+        format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))
+    };
+    {} => {
+        format!("{}:{}", file!(), line!())
+    };
+}
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index 1c43a04..7cf1819 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -14,6 +14,7 @@
 
 //! This module implements methods to load legacy keystore key blob files.
 
+use crate::ks_err;
 use crate::{
     error::{Error as KsError, ResponseCode},
     key_parameter::{KeyParameter, KeyParameterValue},
@@ -348,24 +349,23 @@
                     None
                 }
                 _ => {
-                    return Err(Error::BadEncoding)
-                        .context("In decode_alias: could not decode filename.")
+                    return Err(Error::BadEncoding).context(ks_err!("could not decode filename."));
                 }
             };
         }
         if multi.is_some() {
-            return Err(Error::BadEncoding).context("In decode_alias: could not decode filename.");
+            return Err(Error::BadEncoding).context(ks_err!("could not decode filename."));
         }
 
-        String::from_utf8(s).context("In decode_alias: encoded alias was not valid UTF-8.")
+        String::from_utf8(s).context(ks_err!("encoded alias was not valid UTF-8."))
     }
 
     fn new_from_stream(stream: &mut dyn Read) -> Result<Blob> {
         let mut buffer = Vec::new();
-        stream.read_to_end(&mut buffer).context("In new_from_stream.")?;
+        stream.read_to_end(&mut buffer).context(ks_err!())?;
 
         if buffer.len() < Self::COMMON_HEADER_SIZE {
-            return Err(Error::BadLen).context("In new_from_stream.")?;
+            return Err(Error::BadLen).context(ks_err!())?;
         }
 
         let version: u8 = buffer[Self::VERSION_OFFSET];
@@ -380,15 +380,15 @@
 
         if version != SUPPORTED_LEGACY_BLOB_VERSION {
             return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-                .context(format!("In new_from_stream: Unknown blob version: {}.", version));
+                .context(ks_err!("Unknown blob version: {}.", version));
         }
 
         let length = u32::from_be_bytes(
             buffer[Self::LENGTH_OFFSET..Self::LENGTH_OFFSET + 4].try_into().unwrap(),
         ) as usize;
         if buffer.len() < Self::COMMON_HEADER_SIZE + length {
-            return Err(Error::BadLen).context(format!(
-                "In new_from_stream. Expected: {} got: {}.",
+            return Err(Error::BadLen).context(ks_err!(
+                "Expected: {} got: {}.",
                 Self::COMMON_HEADER_SIZE + length,
                 buffer.len()
             ));
@@ -457,11 +457,12 @@
             }),
             (blob_types::SUPER_KEY, _, None) | (blob_types::SUPER_KEY_AES256, _, None) => {
                 Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-                    .context("In new_from_stream: Super key without salt for key derivation.")
+                    .context(ks_err!("Super key without salt for key derivation."))
             }
-            _ => Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
-                "In new_from_stream: Unknown blob type. {} {}",
-                blob_type, is_encrypted
+            _ => Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
+                "Unknown blob type. {} {}",
+                blob_type,
+                is_encrypted
             )),
         }
     }
@@ -482,30 +483,23 @@
     where
         F: FnOnce(&[u8], &[u8], &[u8], Option<&[u8]>, Option<usize>) -> Result<ZVec>,
     {
-        let blob =
-            Self::new_from_stream(&mut stream).context("In new_from_stream_decrypt_with.")?;
+        let blob = Self::new_from_stream(&mut stream).context(ks_err!())?;
 
         match blob.value() {
             BlobValue::Encrypted { iv, tag, data } => Ok(Blob {
                 flags: blob.flags,
-                value: BlobValue::Decrypted(
-                    decrypt(data, iv, tag, None, None)
-                        .context("In new_from_stream_decrypt_with.")?,
-                ),
+                value: BlobValue::Decrypted(decrypt(data, iv, tag, None, None).context(ks_err!())?),
             }),
             BlobValue::PwEncrypted { iv, tag, data, salt, key_size } => Ok(Blob {
                 flags: blob.flags,
                 value: BlobValue::Decrypted(
-                    decrypt(data, iv, tag, Some(salt), Some(*key_size))
-                        .context("In new_from_stream_decrypt_with.")?,
+                    decrypt(data, iv, tag, Some(salt), Some(*key_size)).context(ks_err!())?,
                 ),
             }),
             BlobValue::EncryptedGeneric { iv, tag, data } => Ok(Blob {
                 flags: blob.flags,
                 value: BlobValue::Generic(
-                    decrypt(data, iv, tag, None, None)
-                        .context("In new_from_stream_decrypt_with.")?[..]
-                        .to_vec(),
+                    decrypt(data, iv, tag, None, None).context(ks_err!())?[..].to_vec(),
                 ),
             }),
 
@@ -548,33 +542,30 @@
     /// | 32 bit indirect_offset |    Offset from the beginning of the indirect section.
     /// +------------------------+
     pub fn read_key_parameters(stream: &mut &[u8]) -> Result<Vec<KeyParameterValue>> {
-        let indirect_size =
-            read_ne_u32(stream).context("In read_key_parameters: While reading indirect size.")?;
+        let indirect_size = read_ne_u32(stream).context(ks_err!("While reading indirect size."))?;
 
         let indirect_buffer = stream
             .get(0..indirect_size as usize)
             .ok_or(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-            .context("In read_key_parameters: While reading indirect buffer.")?;
+            .context(ks_err!("While reading indirect buffer."))?;
 
         // update the stream position.
         *stream = &stream[indirect_size as usize..];
 
-        let element_count =
-            read_ne_u32(stream).context("In read_key_parameters: While reading element count.")?;
-        let element_size =
-            read_ne_u32(stream).context("In read_key_parameters: While reading element size.")?;
+        let element_count = read_ne_u32(stream).context(ks_err!("While reading element count."))?;
+        let element_size = read_ne_u32(stream).context(ks_err!("While reading element size."))?;
 
         let mut element_stream = stream
             .get(0..element_size as usize)
             .ok_or(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-            .context("In read_key_parameters: While reading elements buffer.")?;
+            .context(ks_err!("While reading elements buffer."))?;
 
         // update the stream position.
         *stream = &stream[element_size as usize..];
 
         let mut params: Vec<KeyParameterValue> = Vec::new();
         for _ in 0..element_count {
-            let tag = Tag(read_ne_i32(&mut element_stream).context("In read_key_parameters.")?);
+            let tag = Tag(read_ne_i32(&mut element_stream).context(ks_err!())?);
             let param = match Self::tag_type(tag) {
                 TagType::ENUM | TagType::ENUM_REP | TagType::UINT | TagType::UINT_REP => {
                     KeyParameterValue::new_from_tag_primitive_pair(
@@ -617,7 +608,7 @@
                 TagType::INVALID => Err(anyhow::anyhow!("Invalid.")),
                 _ => {
                     return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-                        .context("In read_key_parameters: Encountered bogus tag type.");
+                        .context(ks_err!("Encountered bogus tag type."));
                 }
             };
             if let Ok(p) = param {
@@ -647,9 +638,11 @@
             {
                 Ok(Blob {
                     value: BlobValue::Characteristics(
-                        super_key.as_ref().unwrap().decrypt(&data, &iv, &tag).context(
-                            "In decrypt_if_required: Failed to decrypt EncryptedCharacteristics",
-                        )?[..]
+                        super_key
+                            .as_ref()
+                            .unwrap()
+                            .decrypt(&data, &iv, &tag)
+                            .context(ks_err!("Failed to decrypt EncryptedCharacteristics"))?[..]
                             .to_vec(),
                     ),
                     flags,
@@ -664,7 +657,7 @@
                             .as_ref()
                             .unwrap()
                             .decrypt(&data, &iv, &tag)
-                            .context("In decrypt_if_required: Failed to decrypt Encrypted")?,
+                            .context(ks_err!("Failed to decrypt Encrypted"))?,
                     ),
                     flags,
                 })
@@ -678,7 +671,7 @@
                             .as_ref()
                             .unwrap()
                             .decrypt(&data, &iv, &tag)
-                            .context("In decrypt_if_required: Failed to decrypt Encrypted")?[..]
+                            .context(ks_err!("Failed to decrypt Encrypted"))?[..]
                             .to_vec(),
                     ),
                     flags,
@@ -687,7 +680,7 @@
             // This arm catches all encrypted cases where super key is not present or cannot
             // decrypt the blob, the latter being BlobValue::PwEncrypted.
             _ => Err(Error::LockedComponent)
-                .context("In decrypt_if_required: Encountered encrypted blob without super key."),
+                .context(ks_err!("Encountered encrypted blob without super key.")),
         }
     }
 
@@ -700,7 +693,7 @@
         super_key: &Option<Arc<dyn AesGcm>>,
     ) -> Result<LegacyKeyCharacteristics> {
         let blob = Self::read_generic_blob(&self.make_chr_filename(uid, alias, prefix))
-            .context("In read_characteristics_file")?;
+            .context(ks_err!())?;
 
         let blob = match blob {
             None => return Ok(LegacyKeyCharacteristics::Cache(Vec::new())),
@@ -708,16 +701,14 @@
         };
 
         let blob = Self::decrypt_if_required(super_key, blob)
-            .context("In read_characteristics_file: Trying to decrypt blob.")?;
+            .context(ks_err!("Trying to decrypt blob."))?;
 
         let (mut stream, is_cache) = match blob.value() {
             BlobValue::Characteristics(data) => (&data[..], false),
             BlobValue::CharacteristicsCache(data) => (&data[..], true),
             _ => {
-                return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(concat!(
-                    "In read_characteristics_file: ",
-                    "Characteristics file does not hold key characteristics."
-                ))
+                return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
+                    .context(ks_err!("Characteristics file does not hold key characteristics."));
             }
         };
 
@@ -726,7 +717,7 @@
             // the hardware enforced list.
             BlobValue::CharacteristicsCache(_) => Some(
                 Self::read_key_parameters(&mut stream)
-                    .context("In read_characteristics_file.")?
+                    .context(ks_err!())?
                     .into_iter()
                     .map(|value| KeyParameter::new(value, hw_sec_level)),
             ),
@@ -734,7 +725,7 @@
         };
 
         let sw_list = Self::read_key_parameters(&mut stream)
-            .context("In read_characteristics_file.")?
+            .context(ks_err!())?
             .into_iter()
             .map(|value| KeyParameter::new(value, SecurityLevel::KEYSTORE));
 
@@ -786,11 +777,11 @@
             Ok(file) => file,
             Err(e) => match e.kind() {
                 ErrorKind::NotFound => return Ok(None),
-                _ => return Err(e).context("In read_generic_blob."),
+                _ => return Err(e).context(ks_err!()),
             },
         };
 
-        Ok(Some(Self::new_from_stream(&mut file).context("In read_generic_blob.")?))
+        Ok(Some(Self::new_from_stream(&mut file).context(ks_err!())?))
     }
 
     fn read_generic_blob_decrypt_with<F>(path: &Path, decrypt: F) -> Result<Option<Blob>>
@@ -801,14 +792,11 @@
             Ok(file) => file,
             Err(e) => match e.kind() {
                 ErrorKind::NotFound => return Ok(None),
-                _ => return Err(e).context("In read_generic_blob_decrypt_with."),
+                _ => return Err(e).context(ks_err!()),
             },
         };
 
-        Ok(Some(
-            Self::new_from_stream_decrypt_with(&mut file, decrypt)
-                .context("In read_generic_blob_decrypt_with.")?,
-        ))
+        Ok(Some(Self::new_from_stream_decrypt_with(&mut file, decrypt).context(ks_err!())?))
     }
 
     /// Read a legacy keystore entry blob.
@@ -827,7 +815,7 @@
         };
 
         let blob = Self::read_generic_blob_decrypt_with(&path, decrypt)
-            .context("In read_legacy_keystore_entry: Failed to read blob.")?;
+            .context(ks_err!("Failed to read blob."))?;
 
         Ok(blob.and_then(|blob| match blob.value {
             BlobValue::Generic(blob) => Some(blob),
@@ -848,13 +836,13 @@
         if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
             match e.kind() {
                 ErrorKind::NotFound => return Ok(false),
-                _ => return Err(e).context("In remove_legacy_keystore_entry."),
+                _ => return Err(e).context(ks_err!()),
             }
         }
 
         let user_id = uid_to_android_user(uid);
         self.remove_user_dir_if_empty(user_id)
-            .context("In remove_legacy_keystore_entry: Trying to remove empty user dir.")?;
+            .context(ks_err!("Trying to remove empty user dir."))?;
         Ok(true)
     }
 
@@ -869,27 +857,21 @@
             Err(e) => match e.kind() {
                 ErrorKind::NotFound => return Ok(Default::default()),
                 _ => {
-                    return Err(e).context(format!(
-                        concat!(
-                            "In list_legacy_keystore_entries_for_uid: ,",
-                            "Failed to open legacy blob database: {:?}"
-                        ),
-                        path
-                    ))
+                    return Err(e)
+                        .context(ks_err!("Failed to open legacy blob database: {:?}", path));
                 }
             },
         };
         let mut result: Vec<String> = Vec::new();
         for entry in dir {
-            let file_name = entry
-                .context("In list_legacy_keystore_entries_for_uid: Trying to access dir entry")?
-                .file_name();
+            let file_name = entry.context(ks_err!("Trying to access dir entry"))?.file_name();
             if let Some(f) = file_name.to_str() {
                 let encoded_alias = &f[uid_str.len() + 1..];
                 if f.starts_with(&uid_str) && !Self::is_keystore_alias(encoded_alias) {
-                    result.push(Self::decode_alias(encoded_alias).context(
-                        "In list_legacy_keystore_entries_for_uid: Trying to decode alias.",
-                    )?)
+                    result.push(
+                        Self::decode_alias(encoded_alias)
+                            .context(ks_err!("Trying to decode alias."))?,
+                    )
                 }
             }
         }
@@ -911,9 +893,7 @@
         &self,
         user_id: u32,
     ) -> Result<HashMap<u32, HashSet<String>>> {
-        let user_entries = self
-            .list_user(user_id)
-            .context("In list_legacy_keystore_entries_for_user: Trying to list user.")?;
+        let user_entries = self.list_user(user_id).context(ks_err!("Trying to list user."))?;
 
         let result =
             user_entries.into_iter().fold(HashMap::<u32, HashSet<String>>::new(), |mut acc, v| {
@@ -986,9 +966,9 @@
     /// in the database dir.
     pub fn is_empty(&self) -> Result<bool> {
         let dir = Self::with_retry_interrupted(|| fs::read_dir(self.path.as_path()))
-            .context("In is_empty: Failed to open legacy blob database.")?;
+            .context(ks_err!("Failed to open legacy blob database."))?;
         for entry in dir {
-            if (*entry.context("In is_empty: Trying to access dir entry")?.file_name())
+            if (*entry.context(ks_err!("Trying to access dir entry"))?.file_name())
                 .to_str()
                 .map_or(false, |f| f.starts_with("user_"))
             {
@@ -1007,7 +987,7 @@
             return Ok(true);
         }
         Ok(Self::with_retry_interrupted(|| user_path.read_dir())
-            .context("In is_empty_user: Failed to open legacy user dir.")?
+            .context(ks_err!("Failed to open legacy user dir."))?
             .next()
             .is_none())
     }
@@ -1032,16 +1012,14 @@
             Err(e) => match e.kind() {
                 ErrorKind::NotFound => return Ok(Default::default()),
                 _ => {
-                    return Err(e).context(format!(
-                        "In list_user: Failed to open legacy blob database. {:?}",
-                        path
-                    ))
+                    return Err(e)
+                        .context(ks_err!("Failed to open legacy blob database. {:?}", path));
                 }
             },
         };
         let mut result: Vec<String> = Vec::new();
         for entry in dir {
-            let file_name = entry.context("In list_user: Trying to access dir entry")?.file_name();
+            let file_name = entry.context(ks_err!("Trying to access dir entry"))?.file_name();
             if let Some(f) = file_name.to_str() {
                 result.push(f.to_string())
             }
@@ -1055,9 +1033,7 @@
         &self,
         user_id: u32,
     ) -> Result<HashMap<u32, HashSet<String>>> {
-        let user_entries = self
-            .list_user(user_id)
-            .context("In list_keystore_entries_for_user: Trying to list user.")?;
+        let user_entries = self.list_user(user_id).context(ks_err!("Trying to list user."))?;
 
         let result =
             user_entries.into_iter().fold(HashMap::<u32, HashSet<String>>::new(), |mut acc, v| {
@@ -1078,9 +1054,7 @@
     pub fn list_keystore_entries_for_uid(&self, uid: u32) -> Result<Vec<String>> {
         let user_id = uid_to_android_user(uid);
 
-        let user_entries = self
-            .list_user(user_id)
-            .context("In list_keystore_entries_for_uid: Trying to list user.")?;
+        let user_entries = self.list_user(user_id).context(ks_err!("Trying to list user."))?;
 
         let uid_str = format!("{}_", uid);
 
@@ -1163,7 +1137,7 @@
         if something_was_deleted {
             let user_id = uid_to_android_user(uid);
             self.remove_user_dir_if_empty(user_id)
-                .context("In remove_keystore_entry: Trying to remove empty user dir.")?;
+                .context(ks_err!("Trying to remove empty user dir."))?;
         }
 
         Ok(something_was_deleted)
@@ -1188,7 +1162,7 @@
         let dest_path = make_filename(dest_uid, dest_alias, prefix);
         match Self::with_retry_interrupted(|| fs::rename(&src_path, &dest_path)) {
             Err(e) if e.kind() == ErrorKind::NotFound => Ok(()),
-            r => r.context("In move_keystore_file_if_exists: Trying to rename."),
+            r => r.context(ks_err!("Trying to rename.")),
         }
     }
 
@@ -1207,7 +1181,7 @@
         }
 
         if uid_to_android_user(src_uid) != uid_to_android_user(dest_uid) {
-            return Err(Error::AndroidUserMismatch).context("In move_keystore_entry.");
+            return Err(Error::AndroidUserMismatch).context(ks_err!());
         }
 
         let prefixes = ["USRPKEY", "USRSKEY", "USRCERT", "CACERT"];
@@ -1220,12 +1194,7 @@
                 prefix,
                 |uid, alias, prefix| self.make_blob_filename(uid, alias, prefix),
             )
-            .with_context(|| {
-                format!(
-                    "In move_keystore_entry: Trying to move blob file with prefix: \"{}\"",
-                    prefix
-                )
-            })?;
+            .with_context(|| ks_err!("Trying to move blob file with prefix: \"{}\"", prefix))?;
         }
 
         let prefixes = ["USRPKEY", "USRSKEY"];
@@ -1240,8 +1209,8 @@
                 |uid, alias, prefix| self.make_chr_filename(uid, alias, prefix),
             )
             .with_context(|| {
-                format!(
-                    "In move_keystore_entry: Trying to move characteristics file with \
+                ks_err!(
+                    "Trying to move characteristics file with \
                      prefix: \"{}\"",
                     prefix
                 )
@@ -1252,10 +1221,7 @@
     }
 
     fn remove_user_dir_if_empty(&self, user_id: u32) -> Result<()> {
-        if self
-            .is_empty_user(user_id)
-            .context("In remove_user_dir_if_empty: Trying to check for empty user dir.")?
-        {
+        if self.is_empty_user(user_id).context(ks_err!("Trying to check for empty user dir."))? {
             let user_path = self.make_user_path_name(user_id);
             Self::with_retry_interrupted(|| fs::remove_dir(user_path.as_path())).ok();
         }
@@ -1273,14 +1239,14 @@
 
         let km_blob = match km_blob {
             Some((km_blob, prefix)) => {
-                let km_blob =
-                    match km_blob {
-                        Blob { flags: _, value: BlobValue::Decrypted(_) }
-                        | Blob { flags: _, value: BlobValue::Encrypted { .. } } => km_blob,
-                        _ => return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
-                            "In load_by_uid_alias: Found wrong blob type in legacy key blob file.",
-                        ),
-                    };
+                let km_blob = match km_blob {
+                    Blob { flags: _, value: BlobValue::Decrypted(_) }
+                    | Blob { flags: _, value: BlobValue::Encrypted { .. } } => km_blob,
+                    _ => {
+                        return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
+                            .context(ks_err!("Found wrong blob type in legacy key blob file."))
+                    }
+                };
 
                 let hw_sec_level = match km_blob.is_strongbox() {
                     true => SecurityLevel::STRONGBOX,
@@ -1288,7 +1254,7 @@
                 };
                 let key_parameters = self
                     .read_characteristics_file(uid, &prefix, alias, hw_sec_level, super_key)
-                    .context("In load_by_uid_alias.")?;
+                    .context(ks_err!())?;
                 Some((km_blob, key_parameters))
             }
             None => None,
@@ -1296,34 +1262,34 @@
 
         let user_cert_blob =
             Self::read_generic_blob(&self.make_blob_filename(uid, alias, "USRCERT"))
-                .context("In load_by_uid_alias: While loading user cert.")?;
+                .context(ks_err!("While loading user cert."))?;
 
         let user_cert = if let Some(blob) = user_cert_blob {
             let blob = Self::decrypt_if_required(super_key, blob)
-                .context("In load_by_uid_alias: While decrypting user cert.")?;
+                .context(ks_err!("While decrypting user cert."))?;
 
             if let Blob { value: BlobValue::Generic(data), .. } = blob {
                 Some(data)
             } else {
                 return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-                    .context("In load_by_uid_alias: Found unexpected blob type in USRCERT file");
+                    .context(ks_err!("Found unexpected blob type in USRCERT file"));
             }
         } else {
             None
         };
 
         let ca_cert_blob = Self::read_generic_blob(&self.make_blob_filename(uid, alias, "CACERT"))
-            .context("In load_by_uid_alias: While loading ca cert.")?;
+            .context(ks_err!("While loading ca cert."))?;
 
         let ca_cert = if let Some(blob) = ca_cert_blob {
             let blob = Self::decrypt_if_required(super_key, blob)
-                .context("In load_by_uid_alias: While decrypting ca cert.")?;
+                .context(ks_err!("While decrypting ca cert."))?;
 
             if let Blob { value: BlobValue::Generic(data), .. } = blob {
                 Some(data)
             } else {
                 return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
-                    .context("In load_by_uid_alias: Found unexpected blob type in CACERT file");
+                    .context(ks_err!("Found unexpected blob type in CACERT file"));
             }
         } else {
             None
@@ -1340,8 +1306,7 @@
     /// Load and decrypt legacy super key blob.
     pub fn load_super_key(&self, user_id: u32, pw: &Password) -> Result<Option<ZVec>> {
         let path = self.make_super_key_filename(user_id);
-        let blob = Self::read_generic_blob(&path)
-            .context("In load_super_key: While loading super key.")?;
+        let blob = Self::read_generic_blob(&path).context(ks_err!("While loading super key."))?;
 
         let blob = match blob {
             Some(blob) => match blob {
@@ -1349,23 +1314,18 @@
                     if (flags & flags::ENCRYPTED) != 0 {
                         let key = pw
                             .derive_key(&salt, key_size)
-                            .context("In load_super_key: Failed to derive key from password.")?;
-                        let blob = aes_gcm_decrypt(&data, &iv, &tag, &key).context(
-                            "In load_super_key: while trying to decrypt legacy super key blob.",
-                        )?;
+                            .context(ks_err!("Failed to derive key from password."))?;
+                        let blob = aes_gcm_decrypt(&data, &iv, &tag, &key)
+                            .context(ks_err!("while trying to decrypt legacy super key blob."))?;
                         Some(blob)
                     } else {
                         // In 2019 we had some unencrypted super keys due to b/141955555.
-                        Some(
-                            data.try_into()
-                                .context("In load_super_key: Trying to convert key into ZVec")?,
-                        )
+                        Some(data.try_into().context(ks_err!("Trying to convert key into ZVec"))?)
                     }
                 }
                 _ => {
-                    return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
-                        "In load_super_key: Found wrong blob type in legacy super key blob file.",
-                    )
+                    return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
+                        .context(ks_err!("Found wrong blob type in legacy super key blob file."));
                 }
             },
             None => None,
diff --git a/keystore2/src/legacy_importer.rs b/keystore2/src/legacy_importer.rs
index 93e1735..9eb702d 100644
--- a/keystore2/src/legacy_importer.rs
+++ b/keystore2/src/legacy_importer.rs
@@ -20,6 +20,7 @@
 };
 use crate::error::{map_km_error, Error};
 use crate::key_parameter::{KeyParameter, KeyParameterValue};
+use crate::ks_err;
 use crate::legacy_blob::{self, Blob, BlobValue, LegacyKeyCharacteristics};
 use crate::super_key::USER_SUPER_KEY;
 use crate::utils::{
@@ -185,9 +186,8 @@
                 }
                 (Self::STATE_UNINITIALIZED, false) => {
                     // Okay, tough luck. The legacy loader was really completely uninitialized.
-                    return Err(Error::sys()).context(
-                        "In check_state: Legacy loader should not be called uninitialized.",
-                    );
+                    return Err(Error::sys())
+                        .context(ks_err!("Legacy loader should not be called uninitialized."));
                 }
                 (Self::STATE_READY, _) => return Ok(Self::STATE_READY),
                 (s, _) => panic!("Unknown legacy importer state. {} ", s),
@@ -227,7 +227,7 @@
         F: FnOnce(&mut LegacyImporterState) -> Result<T> + Send + 'static,
     {
         // Short circuit if the database is empty or not initialized (error case).
-        match self.check_state().context("In do_serialized: Checking state.") {
+        match self.check_state().context(ks_err!("Checking state.")) {
             Ok(LegacyImporter::STATE_EMPTY) => return None,
             Ok(LegacyImporter::STATE_READY) => {}
             Err(e) => return Some(Err(e)),
@@ -266,7 +266,7 @@
 
         let (new_state, result) = match receiver.recv() {
             Err(e) => {
-                return Some(Err(e).context("In do_serialized. Failed to receive from the sender."))
+                return Some(Err(e).context(ks_err!("Failed to receive from the sender.")));
             }
             Ok(r) => r,
         };
@@ -357,7 +357,7 @@
             Ok(None) => {}
             Err(e) => return Err(e),
         }
-        let pw = pw.try_clone().context("In with_try_import_super_key: Cloning password.")?;
+        let pw = pw.try_clone().context(ks_err!("Cloning password."))?;
         let result = self.do_serialized(move |importer_state| {
             importer_state.check_and_import_super_key(user_id, &pw)
         });
@@ -424,7 +424,7 @@
         };
 
         self.sec_level_to_km_uuid.get(&sec_level).copied().ok_or_else(|| {
-            anyhow::anyhow!(Error::sys()).context("In get_km_uuid: No KM instance for blob.")
+            anyhow::anyhow!(Error::sys()).context(ks_err!("No KM instance for blob."))
         })
     }
 
@@ -446,7 +446,7 @@
         match self
             .db
             .load_super_key(&USER_SUPER_KEY, user_id)
-            .context("In get_super_key_id_check_unlockable_or_delete: Failed to load super key")?
+            .context(ks_err!("Failed to load super key"))?
         {
             Some((_, entry)) => Ok(entry.id()),
             None => {
@@ -460,17 +460,14 @@
                 // key and return NotFound, because the key will never
                 // be unlocked again.
                 if self.legacy_loader.has_super_key(user_id) {
-                    Err(Error::Rc(ResponseCode::LOCKED)).context(
-                        "In get_super_key_id_check_unlockable_or_delete: \
-                         Cannot import super key of this key while user is locked.",
-                    )
+                    Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!(
+                        "Cannot import super key of this key while user is locked."
+                    ))
                 } else {
-                    self.legacy_loader.remove_keystore_entry(uid, alias).context(
-                        "In get_super_key_id_check_unlockable_or_delete: \
-                         Trying to remove obsolete key.",
-                    )?;
-                    Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                        .context("In get_super_key_id_check_unlockable_or_delete: Obsolete key.")
+                    self.legacy_loader
+                        .remove_keystore_entry(uid, alias)
+                        .context(ks_err!("Trying to remove obsolete key."))?;
+                    Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context(ks_err!("Obsolete key."))
                 }
             }
         }
@@ -487,99 +484,91 @@
         let (km_blob, params) = match km_blob_params {
             Some((km_blob, LegacyKeyCharacteristics::File(params))) => (km_blob, params),
             Some((km_blob, LegacyKeyCharacteristics::Cache(params))) => {
-                return Ok((Some((km_blob, params)), None))
+                return Ok((Some((km_blob, params)), None));
             }
             None => return Ok((None, None)),
         };
 
-        let km_uuid = self
-            .get_km_uuid(km_blob.is_strongbox())
-            .context("In characteristics_file_to_cache: Trying to get KM UUID")?;
+        let km_uuid =
+            self.get_km_uuid(km_blob.is_strongbox()).context(ks_err!("Trying to get KM UUID"))?;
 
         let blob = match (&km_blob.value(), super_key.as_ref()) {
             (BlobValue::Encrypted { iv, tag, data }, Some(super_key)) => {
-                let blob = super_key
-                    .decrypt(data, iv, tag)
-                    .context("In characteristics_file_to_cache: Decryption failed.")?;
+                let blob =
+                    super_key.decrypt(data, iv, tag).context(ks_err!("Decryption failed."))?;
                 LegacyBlob::ZVec(blob)
             }
             (BlobValue::Encrypted { .. }, None) => {
-                return Err(Error::Rc(ResponseCode::LOCKED)).context(
-                    "In characteristics_file_to_cache: Oh uh, so close. \
-                     This ancient key cannot be imported unless the user is unlocked.",
-                );
+                return Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!(
+                    "Oh uh, so close. \
+                     This ancient key cannot be imported unless the user is unlocked."
+                ));
             }
             (BlobValue::Decrypted(data), _) => LegacyBlob::Ref(data),
             _ => {
-                return Err(Error::sys())
-                    .context("In characteristics_file_to_cache: Unexpected blob type.")
+                return Err(Error::sys()).context(ks_err!("Unexpected blob type."));
             }
         };
 
-        let (km_params, upgraded_blob) = get_key_characteristics_without_app_data(&km_uuid, &*blob)
-            .context(
-                "In characteristics_file_to_cache: Failed to get key characteristics from device.",
-            )?;
+        let (km_params, upgraded_blob) = get_key_characteristics_without_app_data(&km_uuid, &blob)
+            .context(ks_err!("Failed to get key characteristics from device.",))?;
 
         let flags = km_blob.get_flags();
 
-        let (current_blob, superseded_blob) = if let Some(upgraded_blob) = upgraded_blob {
-            match (km_blob.take_value(), super_key.as_ref()) {
-                (BlobValue::Encrypted { iv, tag, data }, Some(super_key)) => {
-                    let super_key_id =
-                        self.get_super_key_id_check_unlockable_or_delete(uid, alias).context(
-                            "In characteristics_file_to_cache: \
-                             How is there a super key but no super key id?",
-                        )?;
+        let (current_blob, superseded_blob) =
+            if let Some(upgraded_blob) = upgraded_blob {
+                match (km_blob.take_value(), super_key.as_ref()) {
+                    (BlobValue::Encrypted { iv, tag, data }, Some(super_key)) => {
+                        let super_key_id = self
+                            .get_super_key_id_check_unlockable_or_delete(uid, alias)
+                            .context(ks_err!("How is there a super key but no super key id?"))?;
 
-                    let mut superseded_metadata = BlobMetaData::new();
-                    superseded_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
-                    superseded_metadata.add(BlobMetaEntry::AeadTag(tag.to_vec()));
-                    superseded_metadata
-                        .add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
-                    superseded_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
-                    let superseded_blob = (LegacyBlob::Vec(data), superseded_metadata);
+                        let mut superseded_metadata = BlobMetaData::new();
+                        superseded_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
+                        superseded_metadata.add(BlobMetaEntry::AeadTag(tag.to_vec()));
+                        superseded_metadata
+                            .add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
+                        superseded_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
+                        let superseded_blob = (LegacyBlob::Vec(data), superseded_metadata);
 
-                    let (data, iv, tag) = super_key.encrypt(&upgraded_blob).context(
-                        "In characteristics_file_to_cache: \
-                         Failed to encrypt upgraded key blob.",
-                    )?;
-                    (
-                        Blob::new(flags, BlobValue::Encrypted { data, iv, tag }),
-                        Some(superseded_blob),
-                    )
+                        let (data, iv, tag) = super_key
+                            .encrypt(&upgraded_blob)
+                            .context(ks_err!("Failed to encrypt upgraded key blob."))?;
+                        (
+                            Blob::new(flags, BlobValue::Encrypted { data, iv, tag }),
+                            Some(superseded_blob),
+                        )
+                    }
+                    (BlobValue::Encrypted { .. }, None) => {
+                        return Err(Error::sys()).context(ks_err!(
+                            "This should not be reachable. \
+                         The blob could not have been decrypted above."
+                        ));
+                    }
+                    (BlobValue::Decrypted(data), _) => {
+                        let mut superseded_metadata = BlobMetaData::new();
+                        superseded_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
+                        let superseded_blob = (LegacyBlob::ZVec(data), superseded_metadata);
+                        (
+                            Blob::new(
+                                flags,
+                                BlobValue::Decrypted(upgraded_blob.try_into().context(ks_err!(
+                                    "Failed to convert upgraded blob to ZVec."
+                                ))?),
+                            ),
+                            Some(superseded_blob),
+                        )
+                    }
+                    _ => {
+                        return Err(Error::sys()).context(ks_err!(
+                            "This should not be reachable. \
+                         Any other variant should have resulted in a different error."
+                        ));
+                    }
                 }
-                (BlobValue::Encrypted { .. }, None) => {
-                    return Err(Error::sys()).context(
-                        "In characteristics_file_to_cache: This should not be reachable. \
-                         The blob could not have been decrypted above.",
-                    );
-                }
-                (BlobValue::Decrypted(data), _) => {
-                    let mut superseded_metadata = BlobMetaData::new();
-                    superseded_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
-                    let superseded_blob = (LegacyBlob::ZVec(data), superseded_metadata);
-                    (
-                        Blob::new(
-                            flags,
-                            BlobValue::Decrypted(upgraded_blob.try_into().context(
-                                "In characteristics_file_to_cache: \
-                             Failed to convert upgraded blob to ZVec.",
-                            )?),
-                        ),
-                        Some(superseded_blob),
-                    )
-                }
-                _ => {
-                    return Err(Error::sys()).context(
-                        "In characteristics_file_to_cache: This should not be reachable. \
-                         Any other variant should have resulted in a different error.",
-                    )
-                }
-            }
-        } else {
-            (km_blob, None)
-        };
+            } else {
+                (km_blob, None)
+            };
 
         let params =
             augment_legacy_characteristics_file_with_key_characteristics(km_params, params);
@@ -595,10 +584,10 @@
         super_key: Option<Arc<dyn AesGcm>>,
     ) -> Result<()> {
         let alias = key.alias.clone().ok_or_else(|| {
-            anyhow::anyhow!(Error::sys()).context(
-                "In check_and_import: Must be Some because \
-                 our caller must not have called us otherwise.",
-            )
+            anyhow::anyhow!(Error::sys()).context(ks_err!(
+                "Must be Some because \
+                 our caller must not have called us otherwise."
+            ))
         })?;
 
         if self.recently_imported.contains(&RecentImport::new(uid, alias.clone())) {
@@ -632,11 +621,11 @@
                     e
                 }
             })
-            .context("In check_and_import: Trying to load legacy blob.")?;
+            .context(ks_err!("Trying to load legacy blob."))?;
 
         let (km_blob_params, superseded_blob) = self
             .characteristics_file_to_cache(km_blob_params, &super_key, uid, &alias)
-            .context("In check_and_import: Trying to update legacy charateristics.")?;
+            .context(ks_err!("Trying to update legacy characteristics."))?;
 
         let result = match km_blob_params {
             Some((km_blob, params)) => {
@@ -647,7 +636,7 @@
                         // Get super key id for user id.
                         let super_key_id = self
                             .get_super_key_id_check_unlockable_or_delete(uid, &alias)
-                            .context("In check_and_import: Failed to get super key id.")?;
+                            .context(ks_err!("Failed to get super key id."))?;
 
                         let mut blob_metadata = BlobMetaData::new();
                         blob_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
@@ -659,18 +648,17 @@
                     BlobValue::Decrypted(data) => (LegacyBlob::ZVec(data), BlobMetaData::new()),
                     _ => {
                         return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                            .context("In check_and_import: Legacy key has unexpected type.")
+                            .context(ks_err!("Legacy key has unexpected type."));
                     }
                 };
 
-                let km_uuid = self
-                    .get_km_uuid(is_strongbox)
-                    .context("In check_and_import: Trying to get KM UUID")?;
+                let km_uuid =
+                    self.get_km_uuid(is_strongbox).context(ks_err!("Trying to get KM UUID"))?;
                 blob_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
 
                 let mut metadata = KeyMetaData::new();
-                let creation_date = DateTime::now()
-                    .context("In check_and_import: Trying to make creation time.")?;
+                let creation_date =
+                    DateTime::now().context(ks_err!("Trying to make creation time."))?;
                 metadata.add(KeyMetaEntry::CreationDate(creation_date));
 
                 let blob_info = BlobInfo::new_with_superseded(
@@ -689,18 +677,18 @@
                         &metadata,
                         &km_uuid,
                     )
-                    .context("In check_and_import.")?;
+                    .context(ks_err!())?;
                 Ok(())
             }
             None => {
                 if let Some(ca_cert) = ca_cert {
                     self.db
                         .store_new_certificate(&key, KeyType::Client, &ca_cert, &KEYSTORE_UUID)
-                        .context("In check_and_import: Failed to insert new certificate.")?;
+                        .context(ks_err!("Failed to insert new certificate."))?;
                     Ok(())
                 } else {
                     Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                        .context("In check_and_import: Legacy key not found.")
+                        .context(ks_err!("Legacy key not found."))
                 }
             }
         };
@@ -712,7 +700,7 @@
                 // Delete legacy key from the file system
                 self.legacy_loader
                     .remove_keystore_entry(uid, &alias)
-                    .context("In check_and_import: Trying to remove imported key.")?;
+                    .context(ks_err!("Trying to remove imported key."))?;
                 Ok(())
             }
             Err(e) => Err(e),
@@ -727,11 +715,11 @@
         if let Some(super_key) = self
             .legacy_loader
             .load_super_key(user_id, pw)
-            .context("In check_and_import_super_key: Trying to load legacy super key.")?
+            .context(ks_err!("Trying to load legacy super key."))?
         {
             let (blob, blob_metadata) =
                 crate::super_key::SuperKeyManager::encrypt_with_password(&super_key, pw)
-                    .context("In check_and_import_super_key: Trying to encrypt super key.")?;
+                    .context(ks_err!("Trying to encrypt super key."))?;
 
             self.db
                 .store_super_key(
@@ -741,16 +729,12 @@
                     &blob_metadata,
                     &KeyMetaData::new(),
                 )
-                .context(concat!(
-                    "In check_and_import_super_key: ",
-                    "Trying to insert legacy super_key into the database."
-                ))?;
+                .context(ks_err!("Trying to insert legacy super_key into the database."))?;
             self.legacy_loader.remove_super_key(user_id);
             self.recently_imported_super_key.insert(user_id);
             Ok(())
         } else {
-            Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                .context("In check_and_import_super_key: No key found do import.")
+            Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context(ks_err!("No key found do import."))
         }
     }
 
@@ -765,7 +749,7 @@
             BulkDeleteRequest::Uid(uid) => (
                 self.legacy_loader
                     .list_keystore_entries_for_uid(uid)
-                    .context("In bulk_delete: Trying to get aliases for uid.")
+                    .context(ks_err!("Trying to get aliases for uid."))
                     .map(|aliases| {
                         let mut h = HashMap::<u32, HashSet<String>>::new();
                         h.insert(uid, aliases.into_iter().collect());
@@ -776,7 +760,7 @@
             BulkDeleteRequest::User(user_id) => (
                 self.legacy_loader
                     .list_keystore_entries_for_user(user_id)
-                    .context("In bulk_delete: Trying to get aliases for user_id.")?,
+                    .context(ks_err!("Trying to get aliases for user_id."))?,
                 user_id,
             ),
         };
@@ -784,7 +768,7 @@
         let super_key_id = self
             .db
             .load_super_key(&USER_SUPER_KEY, user_id)
-            .context("In bulk_delete: Failed to load super key")?
+            .context(ks_err!("Failed to load super key"))?
             .map(|(_, entry)| entry.id());
 
         for (uid, alias) in aliases
@@ -794,7 +778,7 @@
             let (km_blob_params, _, _) = self
                 .legacy_loader
                 .load_by_uid_alias(uid, &alias, &None)
-                .context("In bulk_delete: Trying to load legacy blob.")?;
+                .context(ks_err!("Trying to load legacy blob."))?;
 
             // Determine if the key needs special handling to be deleted.
             let (need_gc, is_super_encrypted) = km_blob_params
@@ -848,16 +832,16 @@
                 };
 
                 if let Some((blob, blob_metadata)) = mark_deleted {
-                    self.db.set_deleted_blob(&blob, &blob_metadata).context(concat!(
-                        "In bulk_delete: Trying to insert deleted ",
-                        "blob into the database for garbage collection."
+                    self.db.set_deleted_blob(&blob, &blob_metadata).context(ks_err!(
+                        "Trying to insert deleted \
+                            blob into the database for garbage collection."
                     ))?;
                 }
             }
 
             self.legacy_loader
                 .remove_keystore_entry(uid, &alias)
-                .context("In bulk_delete: Trying to remove imported key.")?;
+                .context(ks_err!("Trying to remove imported key."))?;
         }
         Ok(())
     }
@@ -926,18 +910,18 @@
     blob: &[u8],
 ) -> Result<(Vec<KeyParameter>, Option<Vec<u8>>)> {
     let (km_dev, _) = crate::globals::get_keymint_dev_by_uuid(uuid)
-        .with_context(|| format!("In foo: Trying to get km device for id {:?}", uuid))?;
+        .with_context(|| ks_err!("Trying to get km device for id {:?}", uuid))?;
 
     let (characteristics, upgraded_blob) = upgrade_keyblob_if_required_with(
         &*km_dev,
         blob,
         &[],
         |blob| {
-            let _wd = wd::watch_millis("In foo: Calling GetKeyCharacteristics.", 500);
+            let _wd = wd::watch_millis("Calling GetKeyCharacteristics.", 500);
             map_km_error(km_dev.getKeyCharacteristics(blob, &[], &[]))
         },
         |_| Ok(()),
     )
-    .context("In foo.")?;
+    .context(ks_err!())?;
     Ok((key_characteristics_to_internal(characteristics), upgraded_blob))
 }
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 4a23843..0b830be 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -28,6 +28,7 @@
 pub mod id_rotation;
 /// Internal Representation of Key Parameter and convenience functions.
 pub mod key_parameter;
+pub mod ks_err;
 pub mod legacy_blob;
 pub mod legacy_importer;
 pub mod maintenance;
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 1fca5d9..5efb798 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -20,6 +20,7 @@
 use crate::error::Error;
 use crate::globals::get_keymint_device;
 use crate::globals::{DB, LEGACY_IMPORTER, SUPER_KEY};
+use crate::ks_err;
 use crate::permission::{KeyPerm, KeystorePerm};
 use crate::super_key::{SuperKeyManager, UserState};
 use crate::utils::{
@@ -71,8 +72,7 @@
     fn on_user_password_changed(user_id: i32, password: Option<Password>) -> Result<()> {
         // Check permission. Function should return if this failed. Therefore having '?' at the end
         // is very important.
-        check_keystore_permission(KeystorePerm::ChangePassword)
-            .context("In on_user_password_changed.")?;
+        check_keystore_permission(KeystorePerm::ChangePassword).context(ks_err!())?;
 
         let mut skm = SUPER_KEY.write().unwrap();
 
@@ -80,7 +80,7 @@
             DB.with(|db| {
                 skm.unlock_screen_lock_bound_key(&mut db.borrow_mut(), user_id as u32, pw)
             })
-            .context("In on_user_password_changed: unlock_screen_lock_bound_key failed")?;
+            .context(ks_err!("unlock_screen_lock_bound_key failed"))?;
         }
 
         match DB
@@ -92,12 +92,11 @@
                     password.as_ref(),
                 )
             })
-            .context("In on_user_password_changed.")?
+            .context(ks_err!())?
         {
             UserState::LskfLocked => {
                 // Error - password can not be changed when the device is locked
-                Err(Error::Rc(ResponseCode::LOCKED))
-                    .context("In on_user_password_changed. Device is locked.")
+                Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked."))
             }
             _ => {
                 // LskfLocked is the only error case for password change
@@ -109,7 +108,7 @@
     fn add_or_remove_user(&self, user_id: i32) -> Result<()> {
         // Check permission. Function should return if this failed. Therefore having '?' at the end
         // is very important.
-        check_keystore_permission(KeystorePerm::ChangeUser).context("In add_or_remove_user.")?;
+        check_keystore_permission(KeystorePerm::ChangeUser).context(ks_err!())?;
 
         DB.with(|db| {
             SUPER_KEY.write().unwrap().reset_user(
@@ -119,10 +118,10 @@
                 false,
             )
         })
-        .context("In add_or_remove_user: Trying to delete keys from db.")?;
+        .context(ks_err!("Trying to delete keys from db."))?;
         self.delete_listener
             .delete_user(user_id as u32)
-            .context("In add_or_remove_user: While invoking the delete listener.")
+            .context(ks_err!("While invoking the delete listener."))
     }
 
     fn clear_namespace(&self, domain: Domain, nspace: i64) -> Result<()> {
@@ -131,12 +130,12 @@
 
         LEGACY_IMPORTER
             .bulk_delete_uid(domain, nspace)
-            .context("In clear_namespace: Trying to delete legacy keys.")?;
+            .context(ks_err!("Trying to delete legacy keys."))?;
         DB.with(|db| db.borrow_mut().unbind_keys_for_namespace(domain, nspace))
-            .context("In clear_namespace: Trying to delete keys from db.")?;
+            .context(ks_err!("Trying to delete keys from db."))?;
         self.delete_listener
             .delete_namespace(domain, nspace)
-            .context("In clear_namespace: While invoking the delete listener.")
+            .context(ks_err!("While invoking the delete listener."))
     }
 
     fn get_state(user_id: i32) -> Result<AidlUserState> {
@@ -151,7 +150,7 @@
                     user_id as u32,
                 )
             })
-            .context("In get_state. Trying to get UserState.")?;
+            .context(ks_err!("Trying to get UserState."))?;
 
         match state {
             UserState::Uninitialized => Ok(AidlUserState::UNINITIALIZED),
@@ -164,13 +163,13 @@
     where
         F: Fn(Strong<dyn IKeyMintDevice>) -> binder::Result<()>,
     {
-        let (km_dev, _, _) = get_keymint_device(&sec_level)
-            .context("In call_with_watchdog: getting keymint device")?;
+        let (km_dev, _, _) =
+            get_keymint_device(&sec_level).context(ks_err!("getting keymint device"))?;
 
         let _wp = wd::watch_millis_with("In call_with_watchdog", 500, move || {
             format!("Seclevel: {:?} Op: {}", sec_level, name)
         });
-        map_km_error(op(km_dev)).with_context(|| format!("In keymint device: calling {}", name))?;
+        map_km_error(op(km_dev)).with_context(|| ks_err!("calling {}", name))?;
         Ok(())
     }
 
@@ -203,7 +202,7 @@
 
     fn early_boot_ended() -> Result<()> {
         check_keystore_permission(KeystorePerm::EarlyBootEnded)
-            .context("In early_boot_ended. Checking permission")?;
+            .context(ks_err!("Checking permission"))?;
         log::info!("In early_boot_ended.");
 
         if let Err(e) =
@@ -216,7 +215,7 @@
 
     fn on_device_off_body() -> Result<()> {
         // Security critical permission check. This statement must return on fail.
-        check_keystore_permission(KeystorePerm::ReportOffBody).context("In on_device_off_body.")?;
+        check_keystore_permission(KeystorePerm::ReportOffBody).context(ks_err!())?;
 
         DB.with(|db| db.borrow_mut().update_last_off_body(MonotonicRawTime::now()));
         Ok(())
@@ -228,20 +227,16 @@
         match source.domain {
             Domain::SELINUX | Domain::KEY_ID | Domain::APP => (),
             _ => {
-                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                    "In migrate_key_namespace: \
-                     Source domain must be one of APP, SELINUX, or KEY_ID.",
-                )
+                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
+                    .context(ks_err!("Source domain must be one of APP, SELINUX, or KEY_ID."));
             }
         };
 
         match destination.domain {
             Domain::SELINUX | Domain::APP => (),
             _ => {
-                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                    "In migrate_key_namespace: \
-                     Destination domain must be one of APP or SELINUX.",
-                )
+                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
+                    .context(ks_err!("Destination domain must be one of APP or SELINUX."));
             }
         };
 
@@ -264,7 +259,7 @@
                         },
                     )
                 })
-                .context("In migrate_key_namespace: Failed to load key blob.")?;
+                .context(ks_err!("Failed to load key blob."))?;
             {
                 db.borrow_mut().migrate_key_namespace(key_id_guard, destination, calling_uid, |k| {
                     check_key_permission(KeyPerm::Rebind, k, &None)
@@ -276,7 +271,7 @@
     fn delete_all_keys() -> Result<()> {
         // Security critical permission check. This statement must return on fail.
         check_keystore_permission(KeystorePerm::DeleteAllKeys)
-            .context("In delete_all_keys. Checking permission")?;
+            .context(ks_err!("Checking permission"))?;
         log::info!("In delete_all_keys.");
 
         Maintenance::call_on_all_security_levels("deleteAllKeys", |dev| dev.deleteAllKeys())
diff --git a/keystore2/src/metrics.rs b/keystore2/src/metrics.rs
index 3d8d6d3..cd1cd75 100644
--- a/keystore2/src/metrics.rs
+++ b/keystore2/src/metrics.rs
@@ -15,6 +15,7 @@
 //! This module implements the IKeystoreMetrics AIDL interface, which exposes the API method for the
 //! proxy in the system server to pull the aggregated metrics in keystore.
 use crate::error::map_or_log_err;
+use crate::ks_err;
 use crate::metrics_store::METRICS_STORE;
 use crate::permission::KeystorePerm;
 use crate::utils::{check_keystore_permission, watchdog as wd};
@@ -41,7 +42,7 @@
     fn pull_metrics(&self, atom_id: AtomID) -> Result<Vec<KeystoreAtom>> {
         // Check permission. Function should return if this failed. Therefore having '?' at the end
         // is very important.
-        check_keystore_permission(KeystorePerm::PullMetrics).context("In pull_metrics.")?;
+        check_keystore_permission(KeystorePerm::PullMetrics).context(ks_err!())?;
         METRICS_STORE.get_atoms(atom_id)
     }
 }
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
index 5e88052..6043612 100644
--- a/keystore2/src/metrics_store.rs
+++ b/keystore2/src/metrics_store.rs
@@ -20,6 +20,7 @@
 use crate::error::{get_error_code, Error};
 use crate::globals::DB;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
+use crate::ks_err;
 use crate::operation::Outcome;
 use crate::remote_provisioning::get_pool_status;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
@@ -566,9 +567,9 @@
         let expired_by = SystemTime::now()
             .checked_add(Duration::from_secs(60 * 60 * 24 * 3))
             .ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR))
-            .context("In pull_attestation_pool_stats: Failed to compute expired by system time.")?
+            .context(ks_err!("Failed to compute expired by system time."))?
             .duration_since(UNIX_EPOCH)
-            .context("In pull_attestation_pool_stats: Failed to compute expired by duration.")?
+            .context(ks_err!("Failed to compute expired by duration."))?
             .as_millis() as i64;
 
         let result = get_pool_status(expired_by, *sec_level);
@@ -651,8 +652,8 @@
 /// Read the system property: keystore.crash_count.
 pub fn read_keystore_crash_count() -> Result<i32> {
     rustutils::system_properties::read("keystore.crash_count")
-        .context("In read_keystore_crash_count: Failed read property.")?
-        .context("In read_keystore_crash_count: Property not set.")?
+        .context(ks_err!("Failed read property."))?
+        .context(ks_err!("Property not set."))?
         .parse::<i32>()
         .map_err(std::convert::Into::into)
 }
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 4f33ba6..2034a8a 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -127,6 +127,7 @@
 
 use crate::enforcements::AuthInfo;
 use crate::error::{map_err_with, map_km_error, map_or_log_err, Error, ErrorCode, ResponseCode};
+use crate::ks_err;
 use crate::metrics_store::log_key_operation_event_stats;
 use crate::utils::watchdog as wd;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
@@ -320,10 +321,8 @@
         let guard = self.outcome.lock().expect("In check_active.");
         match *guard {
             Outcome::Unknown => Ok(guard),
-            _ => Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)).context(format!(
-                "In check_active: Call on finalized operation with outcome: {:?}.",
-                *guard
-            )),
+            _ => Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE))
+                .context(ks_err!("Call on finalized operation with outcome: {:?}.", *guard)),
         }
     }
 
@@ -358,13 +357,13 @@
             .lock()
             .unwrap()
             .before_update()
-            .context("In update_aad: Trying to get auth tokens.")?;
+            .context(ks_err!("Trying to get auth tokens."))?;
 
-        self.update_outcome(&mut *outcome, {
+        self.update_outcome(&mut outcome, {
             let _wp = wd::watch_millis("Operation::update_aad: calling updateAad", 500);
             map_km_error(self.km_op.updateAad(aad_input, hat.as_ref(), tst.as_ref()))
         })
-        .context("In update_aad: KeyMint::update failed.")?;
+        .context(ks_err!("Update failed."))?;
 
         Ok(())
     }
@@ -381,14 +380,14 @@
             .lock()
             .unwrap()
             .before_update()
-            .context("In update: Trying to get auth tokens.")?;
+            .context(ks_err!("Trying to get auth tokens."))?;
 
         let output = self
-            .update_outcome(&mut *outcome, {
+            .update_outcome(&mut outcome, {
                 let _wp = wd::watch_millis("Operation::update: calling update", 500);
                 map_km_error(self.km_op.update(input, hat.as_ref(), tst.as_ref()))
             })
-            .context("In update: KeyMint::update failed.")?;
+            .context(ks_err!("Update failed."))?;
 
         if output.is_empty() {
             Ok(None)
@@ -411,10 +410,10 @@
             .lock()
             .unwrap()
             .before_finish()
-            .context("In finish: Trying to get auth tokens.")?;
+            .context(ks_err!("Trying to get auth tokens."))?;
 
         let output = self
-            .update_outcome(&mut *outcome, {
+            .update_outcome(&mut outcome, {
                 let _wp = wd::watch_millis("Operation::finish: calling finish", 500);
                 map_km_error(self.km_op.finish(
                     input,
@@ -424,7 +423,7 @@
                     confirmation_token.as_deref(),
                 ))
             })
-            .context("In finish: KeyMint::finish failed.")?;
+            .context(ks_err!("Finish failed."))?;
 
         self.auth_info.lock().unwrap().after_finish().context("In finish.")?;
 
@@ -447,7 +446,7 @@
 
         {
             let _wp = wd::watch_millis("Operation::abort: calling abort", 500);
-            map_km_error(self.km_op.abort()).context("In abort: KeyMint::abort failed.")
+            map_km_error(self.km_op.abort()).context(ks_err!("KeyMint::abort failed."))
         }
     }
 }
@@ -798,7 +797,7 @@
                         result
                     }
                     None => Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE))
-                        .context("In KeystoreOperation::with_locked_operation"),
+                        .context(ks_err!("KeystoreOperation::with_locked_operation")),
                 };
 
                 if delete_op {
@@ -811,7 +810,7 @@
                 result
             }
             Err(_) => Err(Error::Rc(ResponseCode::OPERATION_BUSY))
-                .context("In KeystoreOperation::with_locked_operation"),
+                .context(ks_err!("KeystoreOperation::with_locked_operation")),
         }
     }
 }
@@ -823,7 +822,7 @@
         let _wp = wd::watch_millis("IKeystoreOperation::updateAad", 500);
         map_or_log_err(
             self.with_locked_operation(
-                |op| op.update_aad(aad_input).context("In KeystoreOperation::updateAad"),
+                |op| op.update_aad(aad_input).context(ks_err!("KeystoreOperation::updateAad")),
                 false,
             ),
             Ok,
@@ -834,7 +833,7 @@
         let _wp = wd::watch_millis("IKeystoreOperation::update", 500);
         map_or_log_err(
             self.with_locked_operation(
-                |op| op.update(input).context("In KeystoreOperation::update"),
+                |op| op.update(input).context(ks_err!("KeystoreOperation::update")),
                 false,
             ),
             Ok,
@@ -848,7 +847,7 @@
         let _wp = wd::watch_millis("IKeystoreOperation::finish", 500);
         map_or_log_err(
             self.with_locked_operation(
-                |op| op.finish(input, signature).context("In KeystoreOperation::finish"),
+                |op| op.finish(input, signature).context(ks_err!("KeystoreOperation::finish")),
                 true,
             ),
             Ok,
@@ -859,7 +858,7 @@
         let _wp = wd::watch_millis("IKeystoreOperation::abort", 500);
         map_err_with(
             self.with_locked_operation(
-                |op| op.abort(Outcome::Abort).context("In KeystoreOperation::abort"),
+                |op| op.abort(Outcome::Abort).context(ks_err!("KeystoreOperation::abort")),
                 true,
             ),
             |e| {
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index f012c1b..d9bdf79 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -20,6 +20,7 @@
 
 use crate::error::Error as KsError;
 use crate::error::ResponseCode;
+use crate::ks_err;
 use android_system_keystore2::aidl::android::system::keystore2::{
     Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
 };
@@ -302,8 +303,8 @@
     }
 
     for p in access_vec.into_iter() {
-        selinux::check_permission(caller_ctx, &target_context, p).context(format!(
-            "check_grant_permission: check_permission failed. \
+        selinux::check_permission(caller_ctx, &target_context, p).context(ks_err!(
+            "check_permission failed. \
             The caller may have tried to grant a permission that they don't possess. {:?}",
             p
         ))?
@@ -357,10 +358,10 @@
                 return Err(selinux::Error::perm())
                     .context("Trying to access key without ownership.");
             }
-            getcon().context("check_key_permission: getcon failed.")?
+            getcon().context(ks_err!("getcon failed."))?
         }
         Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
-            .context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
+            .context(ks_err!("Domain::SELINUX: Failed to lookup namespace."))?,
         Domain::GRANT => {
             match access_vector {
                 Some(_) => {
@@ -369,9 +370,9 @@
                 }
                 None => {
                     // If DOMAIN_GRANT was selected an access vector must be supplied.
-                    return Err(KsError::sys()).context(
+                    return Err(KsError::sys()).context(ks_err!(
                         "Cannot check permission for Domain::GRANT without access vector.",
-                    );
+                    ));
                 }
             }
         }
@@ -379,11 +380,12 @@
             // We should never be called with `Domain::KEY_ID. The database
             // lookup should have converted this into one of `Domain::APP`
             // or `Domain::SELINUX`.
-            return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
+            return Err(KsError::sys())
+                .context(ks_err!("Cannot check permission for Domain::KEY_ID.",));
         }
         Domain::BLOB => {
             let tctx = lookup_keystore2_key_context(key.nspace)
-                .context("Domain::BLOB: Failed to lookup namespace.")?;
+                .context(ks_err!("Domain::BLOB: Failed to lookup namespace."))?;
             // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
             // permission in addition to the requested permission.
             selinux::check_permission(caller_ctx, &tctx, KeyPerm::ManageBlob)?;
diff --git a/keystore2/src/raw_device.rs b/keystore2/src/raw_device.rs
index 4ce9dce..fe044ee 100644
--- a/keystore2/src/raw_device.rs
+++ b/keystore2/src/raw_device.rs
@@ -22,6 +22,7 @@
     },
     error::{map_km_error, Error, ErrorCode},
     globals::get_keymint_device,
+    ks_err,
     super_key::KeyBlob,
     utils::{key_characteristics_to_internal, watchdog as wd, AID_KEYSTORE},
 };
@@ -152,7 +153,7 @@
         key_type: KeyType,
     ) -> Result<(KeyIdGuard, KeyEntry)> {
         db.load_key_entry(key_desc, key_type, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| Ok(()))
-            .context("In lookup_from_desc: load_key_entry failed.")
+            .context(ks_err!("load_key_entry failed."))
     }
 
     /// Look up the key in the database, and return None if it is absent.
@@ -187,7 +188,7 @@
         // - because it avoids holding database locks during slow
         //   KeyMint operations
         let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc, key_type))
-            .context("In lookup_or_generate_key: first lookup failed")?;
+            .context(ks_err!("first lookup failed"))?;
 
         if let Some((key_id_guard, mut key_entry)) = lookup {
             // If the key is associated with a different km instance
@@ -220,7 +221,7 @@
                             })
                         },
                     )
-                    .context("In lookup_or_generate_key: calling getKeyCharacteristics")?;
+                    .context(ks_err!("calling getKeyCharacteristics"))?;
 
                 if validate_characteristics(&key_characteristics) {
                     return Ok((key_id_guard, key_blob));
@@ -234,7 +235,7 @@
         self.create_and_store_key(db, key_desc, key_type, |km_dev| {
             km_dev.generateKey(params, None)
         })
-        .context("In lookup_or_generate_key: generate_and_store_key failed")?;
+        .context(ks_err!("generate_and_store_key failed"))?;
         Self::lookup_from_desc(db, key_desc, key_type)
             .and_then(|(key_id_guard, mut key_entry)| {
                 Ok((
@@ -246,7 +247,7 @@
                         .context("Missing key blob info.")?,
                 ))
             })
-            .context("In lookup_or_generate_key: second lookup failed")
+            .context(ks_err!("second lookup failed"))
     }
 
     /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
@@ -270,7 +271,7 @@
                     );
                     self.km_dev.upgradeKey(&key_blob, &[])
                 })
-                .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
+                .context(ks_err!("Upgrade failed"))?;
 
                 let mut new_blob_metadata = BlobMetaData::new();
                 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
@@ -281,22 +282,14 @@
                     Some(&upgraded_blob),
                     Some(&new_blob_metadata),
                 )
-                .context(concat!(
-                    "In upgrade_keyblob_if_required_with: ",
-                    "Failed to insert upgraded blob into the database"
-                ))?;
+                .context(ks_err!("Failed to insert upgraded blob into the database"))?;
 
                 Ok((
-                    f(&upgraded_blob).context(
-                        "In upgrade_keyblob_if_required_with: Closure failed after upgrade",
-                    )?,
+                    f(&upgraded_blob).context(ks_err!("Closure failed after upgrade"))?,
                     KeyBlob::NonSensitive(upgraded_blob),
                 ))
             }
-            result => Ok((
-                result.context("In upgrade_keyblob_if_required_with: Closure failed")?,
-                key_blob,
-            )),
+            result => Ok((result.context(ks_err!("Closure failed"))?, key_blob)),
         }
     }
 
@@ -322,15 +315,13 @@
                     self.km_dev.begin(purpose, blob, operation_parameters, auth_token)
                 })
             })
-            .context("In use_key_in_one_step: Failed to begin operation.")?;
-        let operation: Strong<dyn IKeyMintOperation> = begin_result
-            .operation
-            .ok_or_else(Error::sys)
-            .context("In use_key_in_one_step: Operation missing")?;
+            .context(ks_err!("Failed to begin operation."))?;
+        let operation: Strong<dyn IKeyMintOperation> =
+            begin_result.operation.ok_or_else(Error::sys).context(ks_err!("Operation missing"))?;
         map_km_error({
             let _wp = wd::watch_millis("In use_key_in_one_step: calling: finish", 500);
             operation.finish(Some(input), None, None, None, None)
         })
-        .context("In use_key_in_one_step: Failed to finish operation.")
+        .context(ks_err!("Failed to finish operation."))
     }
 }
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index 8ed2be4..fec1b92 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -23,11 +23,13 @@
 
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Algorithm::Algorithm, AttestationKey::AttestationKey, Certificate::Certificate,
-    DeviceInfo::DeviceInfo, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
-    KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue,
-    MacedPublicKey::MacedPublicKey, ProtectedData::ProtectedData, SecurityLevel::SecurityLevel,
+    KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel,
     Tag::Tag,
 };
+use android_hardware_security_rkp::aidl::android::hardware::security::keymint::{
+    DeviceInfo::DeviceInfo, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
+    MacedPublicKey::MacedPublicKey, ProtectedData::ProtectedData,
+};
 use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
     AttestationPoolStatus::AttestationPoolStatus, IRemoteProvisioning::BnRemoteProvisioning,
     IRemoteProvisioning::IRemoteProvisioning,
@@ -48,6 +50,7 @@
 use crate::database::{CertificateChain, KeyIdGuard, KeystoreDB, Uuid};
 use crate::error::{self, map_or_log_err, map_rem_prov_error, Error};
 use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
+use crate::ks_err;
 use crate::metrics_store::log_rkp_error_stats;
 use crate::permission::KeystorePerm;
 use crate::utils::{check_keystore_permission, watchdog as wd};
@@ -152,13 +155,11 @@
         } else {
             match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
                 Err(e) => {
-                    log::error!(
-                        "In get_remote_provisioning_key_and_certs: Error occurred: {:?}",
-                        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,
@@ -174,10 +175,7 @@
                             issuerSubjectName: parse_subject_from_certificate(
                                 &cert_chain.batch_cert,
                             )
-                            .context(concat!(
-                                "In get_remote_provisioning_key_and_certs: Failed to ",
-                                "parse subject."
-                            ))?,
+                            .context(ks_err!("Failed to parse subject."))?,
                         },
                         Certificate { encodedCertificate: cert_chain.cert_chain },
                     ))),
@@ -202,9 +200,9 @@
         if let Some(dev) = self.device_by_sec_level.get(sec_level) {
             Ok(dev.as_ref())
         } else {
-            Err(error::Error::sys()).context(concat!(
-                "In get_dev_by_sec_level: Remote instance for requested security level",
-                " not found."
+            Err(error::Error::sys()).context(ks_err!(
+                "Remote instance for requested security level \
+                not found.",
             ))
         }
     }
@@ -213,11 +211,11 @@
     pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
         let mut result: Self = Default::default();
         let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
-            .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
+            .context(ks_err!("Failed to get TEE Remote Provisioner instance."))?;
         result.curve_by_sec_level.insert(
             SecurityLevel::TRUSTED_ENVIRONMENT,
             dev.getHardwareInfo()
-                .context("In new_native_binder: Failed to get hardware info for the TEE.")?
+                .context(ks_err!("Failed to get hardware info for the TEE."))?
                 .supportedEekCurve,
         );
         result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
@@ -225,7 +223,7 @@
             result.curve_by_sec_level.insert(
                 SecurityLevel::STRONGBOX,
                 dev.getHardwareInfo()
-                    .context("In new_native_binder: Failed to get hardware info for StrongBox.")?
+                    .context(ks_err!("Failed to get hardware info for StrongBox."))?
                     .supportedEekCurve,
             );
             result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
@@ -234,23 +232,24 @@
     }
 
     fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
-        let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
-            "In extract_payload_from_cose_mac: COSE_Mac0 returned from IRPC cannot be parsed",
-        )?;
+        let cose_mac0: Vec<Value> = serde_cbor::from_slice(data)
+            .context(ks_err!("COSE_Mac0 returned from IRPC cannot be parsed"))?;
         if cose_mac0.len() != COSE_MAC0_LEN {
-            return Err(error::Error::sys()).context(format!(
-                "In extract_payload_from_cose_mac: COSE_Mac0 has improper length. \
+            return Err(error::Error::sys()).context(ks_err!(
+                "COSE_Mac0 has improper length. \
                     Expected: {}, Actual: {}",
                 COSE_MAC0_LEN,
                 cose_mac0.len(),
             ));
         }
         match &cose_mac0[COSE_MAC0_PAYLOAD] {
-            Value::Bytes(key) => Ok(serde_cbor::from_slice(key)
-                .context("In extract_payload_from_cose_mac: COSE_Mac0 payload is malformed.")?),
-            _ => Err(error::Error::sys()).context(
-                "In extract_payload_from_cose_mac: COSE_Mac0 payload is the wrong type.",
-            )?,
+            Value::Bytes(key) => {
+                Ok(serde_cbor::from_slice(key)
+                    .context(ks_err!("COSE_Mac0 payload is malformed."))?)
+            }
+            _ => {
+                Err(error::Error::sys()).context(ks_err!("COSE_Mac0 payload is the wrong type."))?
+            }
         }
     }
 
@@ -291,17 +290,17 @@
             device_info,
             protected_data,
         ))
-        .context("In generate_csr: Failed to generate csr")?;
+        .context(ks_err!("Failed to generate csr"))?;
         let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
         for maced_public_key in keys_to_sign {
             mac_and_keys.push(
                 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
-                    .context("In generate_csr: Failed to get the payload from the COSE_Mac0")?,
+                    .context(ks_err!("Failed to get the payload from the COSE_Mac0"))?,
             )
         }
         let cbor_array: Value = Value::Array(mac_and_keys);
         serde_cbor::to_vec(&cbor_array)
-            .context("In generate_csr: Failed to serialize the mac and keys array")
+            .context(ks_err!("Failed to serialize the mac and keys array"))
     }
 
     /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
@@ -329,28 +328,27 @@
     }
 
     fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
-        let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
-            "In parse_cose_mac0_for_coords: COSE_Mac0 returned from IRPC cannot be parsed",
-        )?;
+        let cose_mac0: Vec<Value> = serde_cbor::from_slice(data)
+            .context(ks_err!("COSE_Mac0 returned from IRPC cannot be parsed"))?;
         if cose_mac0.len() != COSE_MAC0_LEN {
-            return Err(error::Error::sys()).context(format!(
-                "In parse_cose_mac0_for_coords: COSE_Mac0 has improper length. \
+            return Err(error::Error::sys()).context(ks_err!(
+                "COSE_Mac0 has improper length. \
                     Expected: {}, Actual: {}",
                 COSE_MAC0_LEN,
                 cose_mac0.len(),
             ));
         }
         let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
-            Value::Bytes(key) => serde_cbor::from_slice(key)
-                .context("In parse_cose_mac0_for_coords: COSE_Key is malformed.")?,
-            _ => Err(error::Error::sys())
-                .context("In parse_cose_mac0_for_coords: COSE_Mac0 payload is the wrong type.")?,
+            Value::Bytes(key) => {
+                serde_cbor::from_slice(key).context(ks_err!("COSE_Key is malformed."))?
+            }
+            _ => {
+                Err(error::Error::sys()).context(ks_err!("COSE_Mac0 payload is the wrong type."))?
+            }
         };
         if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
-            return Err(error::Error::sys()).context(
-                "In parse_cose_mac0_for_coords: \
-                COSE_Key returned from IRPC is lacking required fields",
-            );
+            return Err(error::Error::sys())
+                .context(ks_err!("COSE_Key returned from IRPC is lacking required fields"));
         }
         let mut raw_key: Vec<u8> = vec![0; 64];
         match &cose_key[&COSE_KEY_XCOORD] {
@@ -358,15 +356,15 @@
                 raw_key[0..32].clone_from_slice(x_coord)
             }
             Value::Bytes(x_coord) => {
-                return Err(error::Error::sys()).context(format!(
-                "In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not the right length. \
+                return Err(error::Error::sys()).context(ks_err!(
+                    "COSE_Key X-coordinate is not the right length. \
                 Expected: 32; Actual: {}",
                     x_coord.len()
-                ))
+                ));
             }
             _ => {
                 return Err(error::Error::sys())
-                    .context("In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not a bstr")
+                    .context(ks_err!("COSE_Key X-coordinate is not a bstr"));
             }
         }
         match &cose_key[&COSE_KEY_YCOORD] {
@@ -374,15 +372,15 @@
                 raw_key[32..64].clone_from_slice(y_coord)
             }
             Value::Bytes(y_coord) => {
-                return Err(error::Error::sys()).context(format!(
-                "In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not the right length. \
+                return Err(error::Error::sys()).context(ks_err!(
+                    "COSE_Key Y-coordinate is not the right length. \
                 Expected: 32; Actual: {}",
                     y_coord.len()
-                ))
+                ));
             }
             _ => {
                 return Err(error::Error::sys())
-                    .context("In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not a bstr")
+                    .context(ks_err!("COSE_Key Y-coordinate is not a bstr"));
             }
         }
         Ok(raw_key)
@@ -399,18 +397,17 @@
         sec_level: SecurityLevel,
     ) -> Result<()> {
         let (_, _, uuid) = get_keymint_device(&sec_level)?;
-        let dev = self.get_dev_by_sec_level(&sec_level).context(format!(
-            "In generate_key_pair: Failed to get device for security level {:?}",
-            sec_level
-        ))?;
+        let dev = self
+            .get_dev_by_sec_level(&sec_level)
+            .context(ks_err!("Failed to get device for security level {:?}", sec_level))?;
         let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
         let priv_key =
             map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
-                .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
+                .context(ks_err!("Failed to generated ECDSA keypair."))?;
         let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
-            .context("In generate_key_pair: Failed to parse raw key")?;
+            .context(ks_err!("Failed to parse raw key"))?;
         db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
-            .context("In generate_key_pair: Failed to insert attestation key entry")
+            .context(ks_err!("Failed to insert attestation key entry"))
     }
 
     /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
@@ -472,15 +469,15 @@
                     || get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid),
                     |v| Ok(Some(v)),
                 )
-                .context(concat!(
-                    "In get_rem_prov_attest_key: Failed to get a key after",
-                    "attempting to assign one."
+                .context(ks_err!(
+                    "Failed to get a key after \
+                    attempting to assign one.",
                 ))?
                 .map_or_else(
                     || {
-                        Err(Error::sys()).context(concat!(
-                            "In get_rem_prov_attest_key: Attempted to assign a ",
-                            "key and failed silently. Something is very wrong."
+                        Err(Error::sys()).context(ks_err!(
+                            "Attempted to assign a \
+                            key and failed silently. Something is very wrong.",
                         ))
                     },
                     |(guard, cert_chain)| Ok(Some((guard, cert_chain))),
@@ -499,7 +496,7 @@
 ) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
     let guard_and_chain = db
         .retrieve_attestation_key_and_cert_chain(domain, caller_uid as i64, km_uuid)
-        .context("In get_rem_prov_attest_key_helper: Failed to retrieve a key + cert chain")?;
+        .context(ks_err!("Failed to retrieve a key + cert chain"))?;
     match guard_and_chain {
         Some((guard, cert_chain)) => Ok(Some((guard, cert_chain))),
         // Either this app needs to be assigned a key, or the pool is empty. An error will
@@ -507,7 +504,7 @@
         // should be nudged to provision more keys so keystore can retry.
         None => {
             db.assign_attestation_key(domain, caller_uid as i64, km_uuid)
-                .context("In get_rem_prov_attest_key_helper: Failed to assign a key")?;
+                .context(ks_err!("Failed to assign a key"))?;
             Ok(None)
         }
     }
@@ -625,7 +622,7 @@
 
         let guard_and_cert_chain =
             get_rem_prov_attest_key(Domain::APP, caller_uid as u32, db, &km_uuid)
-                .context("In get_attestation_key")?;
+                .context(ks_err!())?;
         match guard_and_cert_chain {
             Some((_, chain)) => Ok(RemotelyProvisionedKey {
                 keyBlob: chain.private_key.to_vec(),
@@ -634,7 +631,7 @@
             // It should be impossible to get `None`, but handle it just in case as a
             // precaution against future behavioral changes in `get_rem_prov_attest_key`.
             None => Err(error::Error::Rc(ResponseCode::OUT_OF_KEYS))
-                .context("In get_attestation_key: No available attestation keys"),
+                .context(ks_err!("No available attestation keys")),
         }
     }
 
@@ -644,7 +641,7 @@
         let mut result: Self = Default::default();
 
         let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
-            .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
+            .context(ks_err!("Failed to get TEE Remote Provisioner instance."))?;
         if let Some(id) = dev.getHardwareInfo()?.uniqueId {
             result.unique_id_to_sec_level.insert(id, SecurityLevel::TRUSTED_ENVIRONMENT);
         }
@@ -697,7 +694,7 @@
     use serde_cbor::Value;
     use std::collections::BTreeMap;
     use std::sync::{Arc, Mutex};
-    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    use android_hardware_security_rkp::aidl::android::hardware::security::keymint::{
         RpcHardwareInfo::RpcHardwareInfo,
     };
 
@@ -741,6 +738,14 @@
         ) -> binder::Result<Vec<u8>> {
             Err(binder::StatusCode::INVALID_OPERATION.into())
         }
+
+        fn generateCertificateRequestV2(
+            &self,
+            _keys_to_sign: &[MacedPublicKey],
+            _challenge: &[u8],
+        ) -> binder::Result<Vec<u8>> {
+            Err(binder::StatusCode::INVALID_OPERATION.into())
+        }
     }
 
     // Hard coded cert that can be parsed -- the content doesn't matter for testing, only that it's valid.
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 28de1ec..ae49bc8 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -23,6 +23,7 @@
 use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
 use crate::key_parameter::KeyParameter as KsKeyParam;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
+use crate::ks_err;
 use crate::metrics_store::log_key_creation_event_stats;
 use crate::remote_provisioning::RemProvState;
 use crate::super_key::{KeyBlob, SuperKeyManager};
@@ -89,7 +90,7 @@
         id_rotation_state: IdRotationState,
     ) -> Result<(Strong<dyn IKeystoreSecurityLevel>, Uuid)> {
         let (dev, hw_info, km_uuid) = get_keymint_device(&security_level)
-            .context("In KeystoreSecurityLevel::new_native_binder.")?;
+            .context(ks_err!("KeystoreSecurityLevel::new_native_binder."))?;
         let result = BnKeystoreSecurityLevel::new_binder(
             Self {
                 security_level,
@@ -171,7 +172,7 @@
                             user_id,
                             &key_blob,
                         )
-                        .context("In store_new_key. Failed to handle super encryption.")?;
+                        .context(ks_err!("Failed to handle super encryption."))?;
 
                     let mut key_metadata = KeyMetaData::new();
                     key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
@@ -187,14 +188,14 @@
                             &key_metadata,
                             &self.km_uuid,
                         )
-                        .context("In store_new_key.")?;
+                        .context(ks_err!())?;
                     Ok(KeyDescriptor {
                         domain: Domain::KEY_ID,
                         nspace: key_id.id(),
                         ..Default::default()
                     })
                 })
-                .context("In store_new_key.")?,
+                .context(ks_err!())?,
         };
 
         Ok(KeyMetadata {
@@ -221,20 +222,19 @@
         let (km_blob, key_properties, key_id_guard, blob_metadata) = match key.domain {
             Domain::BLOB => {
                 check_key_permission(KeyPerm::Use, key, &None)
-                    .context("In create_operation: checking use permission for Domain::BLOB.")?;
+                    .context(ks_err!("checking use permission for Domain::BLOB."))?;
                 if forced {
-                    check_key_permission(KeyPerm::ReqForcedOp, key, &None).context(
-                        "In create_operation: checking forced permission for Domain::BLOB.",
-                    )?;
+                    check_key_permission(KeyPerm::ReqForcedOp, key, &None)
+                        .context(ks_err!("checking forced permission for Domain::BLOB."))?;
                 }
                 (
                     match &key.blob {
                         Some(blob) => blob,
                         None => {
-                            return Err(Error::sys()).context(concat!(
-                                "In create_operation: Key blob must be specified when",
-                                " using Domain::BLOB."
-                            ))
+                            return Err(Error::sys()).context(ks_err!(
+                                "Key blob must be specified when \
+                                using Domain::BLOB."
+                            ));
                         }
                     },
                     None,
@@ -265,12 +265,12 @@
                             )
                         })
                     })
-                    .context("In create_operation: Failed to load key blob.")?;
+                    .context(ks_err!("Failed to load key blob."))?;
 
                 let (blob, blob_metadata) =
-                    key_entry.take_key_blob_info().ok_or_else(Error::sys).context(concat!(
-                        "In create_operation: Successfully loaded key entry, ",
-                        "but KM blob was missing."
+                    key_entry.take_key_blob_info().ok_or_else(Error::sys).context(ks_err!(
+                        "Successfully loaded key entry, \
+                        but KM blob was missing."
                     ))?;
                 scoping_blob = blob;
 
@@ -285,11 +285,11 @@
 
         let purpose = operation_parameters.iter().find(|p| p.tag == Tag::PURPOSE).map_or(
             Err(Error::Km(ErrorCode::INVALID_ARGUMENT))
-                .context("In create_operation: No operation purpose specified."),
+                .context(ks_err!("No operation purpose specified.")),
             |kp| match kp.value {
                 KeyParameterValue::KeyPurpose(p) => Ok(p),
                 _ => Err(Error::Km(ErrorCode::INVALID_ARGUMENT))
-                    .context("In create_operation: Malformed KeyParameter."),
+                    .context(ks_err!("Malformed KeyParameter.")),
             },
         )?;
 
@@ -306,13 +306,13 @@
                 operation_parameters.as_ref(),
                 self.hw_info.timestampTokenRequired,
             )
-            .context("In create_operation.")?;
+            .context(ks_err!())?;
 
         let km_blob = SUPER_KEY
             .read()
             .unwrap()
             .unwrap_key_if_required(&blob_metadata, km_blob)
-            .context("In create_operation. Failed to handle super encryption.")?;
+            .context(ks_err!("Failed to handle super encryption."))?;
 
         let (begin_result, upgraded_blob) = self
             .upgrade_keyblob_if_required_with(
@@ -354,7 +354,7 @@
                     }
                 },
             )
-            .context("In create_operation: Failed to begin operation.")?;
+            .context(ks_err!("Failed to begin operation."))?;
 
         let operation_challenge = auth_info.finalize_create_authorization(begin_result.challenge);
 
@@ -369,10 +369,10 @@
                 LoggingInfo::new(self.security_level, purpose, op_params, upgraded_blob.is_some()),
             ),
             None => {
-                return Err(Error::sys()).context(concat!(
-                    "In create_operation: Begin operation returned successfully, ",
-                    "but did not return a valid operation."
-                ))
+                return Err(Error::sys()).context(ks_err!(
+                    "Begin operation returned successfully, \
+                    but did not return a valid operation."
+                ));
             }
         };
 
@@ -380,7 +380,7 @@
             KeystoreOperation::new_native_binder(operation)
                 .as_binder()
                 .into_interface()
-                .context("In create_operation: Failed to create IKeystoreOperation.")?;
+                .context(ks_err!("Failed to create IKeystoreOperation."))?;
 
         Ok(CreateOperationResponse {
             iOperation: Some(op_binder),
@@ -407,10 +407,10 @@
         // Unconditionally add the CREATION_DATETIME tag and prevent callers from
         // specifying it.
         if params.iter().any(|kp| kp.tag == Tag::CREATION_DATETIME) {
-            return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                "In KeystoreSecurityLevel::add_required_parameters: \
-                Specifying Tag::CREATION_DATETIME is not allowed.",
-            );
+            return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!(
+                "KeystoreSecurityLevel::add_required_parameters: \
+                Specifying Tag::CREATION_DATETIME is not allowed."
+            ));
         }
 
         // Add CREATION_DATETIME only if the backend version Keymint V1 (100) or newer.
@@ -420,16 +420,16 @@
                 value: KeyParameterValue::DateTime(
                     SystemTime::now()
                         .duration_since(SystemTime::UNIX_EPOCH)
-                        .context(
-                            "In KeystoreSecurityLevel::add_required_parameters: \
-                        Failed to get epoch time.",
-                        )?
+                        .context(ks_err!(
+                            "KeystoreSecurityLevel::add_required_parameters: \
+                                Failed to get epoch time."
+                        ))?
                         .as_millis()
                         .try_into()
-                        .context(
-                            "In KeystoreSecurityLevel::add_required_parameters: \
-                        Failed to convert epoch time.",
-                        )?,
+                        .context(ks_err!(
+                            "KeystoreSecurityLevel::add_required_parameters: \
+                                Failed to convert epoch time."
+                        ))?,
                 ),
             });
         }
@@ -441,9 +441,8 @@
                     "In KeystoreSecurityLevel::add_required_parameters calling: get_aaid",
                     500,
                 );
-                keystore2_aaid::get_aaid(uid).map_err(|e| {
-                    anyhow!(format!("In add_required_parameters: get_aaid returned status {}.", e))
-                })
+                keystore2_aaid::get_aaid(uid)
+                    .map_err(|e| anyhow!(ks_err!("get_aaid returned status {}.", e)))
             }?;
 
             result.push(KeyParameter {
@@ -456,14 +455,15 @@
             if check_key_permission(KeyPerm::GenUniqueId, key, &None).is_err()
                 && check_unique_id_attestation_permissions().is_err()
             {
-                return Err(Error::perm()).context(
-                    "In add_required_parameters: \
-                    Caller does not have the permission to generate a unique ID",
-                );
+                return Err(Error::perm()).context(ks_err!(
+                    "Caller does not have the permission to generate a unique ID"
+                ));
             }
-            if self.id_rotation_state.had_factory_reset_since_id_rotation().context(
-                "In add_required_parameters: Call to had_factory_reset_since_id_rotation failed.",
-            )? {
+            if self
+                .id_rotation_state
+                .had_factory_reset_since_id_rotation()
+                .context(ks_err!("Call to had_factory_reset_since_id_rotation failed."))?
+            {
                 result.push(KeyParameter {
                     tag: Tag::RESET_SINCE_ID_ROTATION,
                     value: KeyParameterValue::BoolValue(true),
@@ -474,8 +474,7 @@
         // If the caller requests any device identifier attestation tag, check that they hold the
         // correct Android permission.
         if params.iter().any(|kp| is_device_id_attestation_tag(kp.tag)) {
-            check_device_attestation_permissions().context(concat!(
-                "In add_required_parameters: ",
+            check_device_attestation_permissions().context(ks_err!(
                 "Caller does not have the permission to attest device identifiers."
             ))?;
         }
@@ -513,7 +512,7 @@
     ) -> Result<KeyMetadata> {
         if key.domain != Domain::BLOB && key.alias.is_none() {
             return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
-                .context("In generate_key: Alias must be specified");
+                .context(ks_err!("Alias must be specified"));
         }
         let caller_uid = ThreadState::get_calling_uid();
 
@@ -529,7 +528,7 @@
 
         // generate_key requires the rebind permission.
         // Must return on error for security reasons.
-        check_key_permission(KeyPerm::Rebind, &key, &None).context("In generate_key.")?;
+        check_key_permission(KeyPerm::Rebind, &key, &None).context(ks_err!())?;
 
         let attestation_key_info = match (key.domain, attest_key_descriptor) {
             (Domain::BLOB, _) => None,
@@ -544,11 +543,11 @@
                         &mut db.borrow_mut(),
                     )
                 })
-                .context("In generate_key: Trying to get an attestation key")?,
+                .context(ks_err!("Trying to get an attestation key"))?,
         };
         let params = self
             .add_required_parameters(caller_uid, params, &key)
-            .context("In generate_key: Trying to get aaid.")?;
+            .context(ks_err!("Trying to get aaid."))?;
 
         let creation_result = match attestation_key_info {
             Some(AttestationKeyInfo::UserGenerated {
@@ -581,7 +580,7 @@
                         })
                     },
                 )
-                .context("In generate_key: Using user generated attestation key.")
+                .context(ks_err!("Using user generated attestation key."))
                 .map(|(result, _)| result),
             Some(AttestationKeyInfo::RemoteProvisioned {
                 key_id_guard,
@@ -629,10 +628,10 @@
             })
             .context("While generating Key without explicit attestation key."),
         }
-        .context("In generate_key.")?;
+        .context(ks_err!())?;
 
         let user_id = uid_to_android_user(caller_uid);
-        self.store_new_key(key, creation_result, user_id, Some(flags)).context("In generate_key.")
+        self.store_new_key(key, creation_result, user_id, Some(flags)).context(ks_err!())
     }
 
     fn import_key(
@@ -645,7 +644,7 @@
     ) -> Result<KeyMetadata> {
         if key.domain != Domain::BLOB && key.alias.is_none() {
             return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
-                .context("In import_key: Alias must be specified");
+                .context(ks_err!("Alias must be specified"));
         }
         let caller_uid = ThreadState::get_calling_uid();
 
@@ -664,7 +663,7 @@
 
         let params = self
             .add_required_parameters(caller_uid, params, &key)
-            .context("In import_key: Trying to get aaid.")?;
+            .context(ks_err!("Trying to get aaid."))?;
 
         let format = params
             .iter()
@@ -680,7 +679,7 @@
                 v => Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
                     .context(format!("Unknown Algorithm {:?}.", v)),
             })
-            .context("In import_key.")?;
+            .context(ks_err!())?;
 
         let km_dev = &self.keymint;
         let creation_result = map_km_error({
@@ -688,10 +687,10 @@
                 self.watch_millis("In KeystoreSecurityLevel::import_key: calling importKey.", 500);
             km_dev.importKey(&params, format, key_data, None /* attestKey */)
         })
-        .context("In import_key: Trying to call importKey")?;
+        .context(ks_err!("Trying to call importKey"))?;
 
         let user_id = uid_to_android_user(caller_uid);
-        self.store_new_key(key, creation_result, user_id, Some(flags)).context("In import_key.")
+        self.store_new_key(key, creation_result, user_id, Some(flags)).context(ks_err!())
     }
 
     fn import_wrapped_key(
@@ -708,20 +707,16 @@
                 domain: Domain::SELINUX, blob: Some(ref blob), alias: Some(_), ..
             } => blob,
             _ => {
-                return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT)).context(format!(
-                    concat!(
-                        "In import_wrapped_key: Alias and blob must be specified ",
-                        "and domain must be APP or SELINUX. {:?}"
-                    ),
+                return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT)).context(ks_err!(
+                    "Alias and blob must be specified and domain must be APP or SELINUX. {:?}",
                     key
-                ))
+                ));
             }
         };
 
         if wrapping_key.domain == Domain::BLOB {
-            return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT)).context(
-                "In import_wrapped_key: Import wrapped key not supported for self managed blobs.",
-            );
+            return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
+                .context(ks_err!("Import wrapped key not supported for self managed blobs."));
         }
 
         let caller_uid = ThreadState::get_calling_uid();
@@ -744,7 +739,7 @@
         };
 
         // Import_wrapped_key requires the rebind permission for the new key.
-        check_key_permission(KeyPerm::Rebind, &key, &None).context("In import_wrapped_key.")?;
+        check_key_permission(KeyPerm::Rebind, &key, &None).context(ks_err!())?;
 
         let super_key = SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(user_id);
 
@@ -771,9 +766,7 @@
             .read()
             .unwrap()
             .unwrap_key_if_required(&wrapping_blob_metadata, &wrapping_key_blob)
-            .context(
-                "In import_wrapped_key. Failed to handle super encryption for wrapping key.",
-            )?;
+            .context(ks_err!("Failed to handle super encryption for wrapping key."))?;
 
         // km_dev.importWrappedKey does not return a certificate chain.
         // TODO Do we assume that all wrapped keys are symmetric?
@@ -820,10 +813,10 @@
                     Ok(creation_result)
                 },
             )
-            .context("In import_wrapped_key.")?;
+            .context(ks_err!())?;
 
         self.store_new_key(key, creation_result, user_id, None)
-            .context("In import_wrapped_key: Trying to store the new key.")
+            .context(ks_err!("Trying to store the new key."))
     }
 
     fn store_upgraded_keyblob(
@@ -834,7 +827,7 @@
     ) -> Result<()> {
         let (upgraded_blob_to_be_stored, new_blob_metadata) =
             SuperKeyManager::reencrypt_if_required(key_blob, upgraded_blob)
-                .context("In store_upgraded_keyblob: Failed to handle super encryption.")?;
+                .context(ks_err!("Failed to handle super encryption."))?;
 
         let mut new_blob_metadata = new_blob_metadata.unwrap_or_default();
         if let Some(uuid) = km_uuid {
@@ -850,7 +843,7 @@
                 Some(&new_blob_metadata),
             )
         })
-        .context("In store_upgraded_keyblob: Failed to insert upgraded blob into the database.")
+        .context(ks_err!("Failed to insert upgraded blob into the database."))
     }
 
     fn upgrade_keyblob_if_required_with<T, F>(
@@ -874,25 +867,22 @@
                 if key_id_guard.is_some() {
                     // Unwrap cannot panic, because the is_some was true.
                     let kid = key_id_guard.take().unwrap();
-                    Self::store_upgraded_keyblob(kid, km_uuid, key_blob, upgraded_blob).context(
-                        "In upgrade_keyblob_if_required_with: store_upgraded_keyblob failed",
-                    )
+                    Self::store_upgraded_keyblob(kid, km_uuid, key_blob, upgraded_blob)
+                        .context(ks_err!("store_upgraded_keyblob failed"))
                 } else {
                     Ok(())
                 }
             },
         )
-        .context("In KeystoreSecurityLevel::upgrade_keyblob_if_required_with.")?;
+        .context(ks_err!())?;
 
         // If no upgrade was needed, use the opportunity to reencrypt the blob if required
         // and if the a key_id_guard is held. Note: key_id_guard can only be Some if no
         // upgrade was performed above and if one was given in the first place.
         if key_blob.force_reencrypt() {
             if let Some(kid) = key_id_guard {
-                Self::store_upgraded_keyblob(kid, km_uuid, key_blob, key_blob).context(concat!(
-                    "In upgrade_keyblob_if_required_with: ",
-                    "store_upgraded_keyblob failed in forced reencrypt"
-                ))?;
+                Self::store_upgraded_keyblob(kid, km_uuid, key_blob, key_blob)
+                    .context(ks_err!("store_upgraded_keyblob failed in forced reencrypt"))?;
             }
         }
         Ok((v, upgraded_blob))
@@ -903,22 +893,18 @@
         storage_key: &KeyDescriptor,
     ) -> Result<EphemeralStorageKeyResponse> {
         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"
-            ));
+            return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
+                .context(ks_err!("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",
-            )?;
+            .context(ks_err!("No key blob specified"))?;
 
         // convert_storage_key_to_ephemeral requires the associated permission
         check_key_permission(KeyPerm::ConvertStorageKeyToEphemeral, storage_key, &None)
-            .context("In convert_storage_key_to_ephemeral: Check permission")?;
+            .context(ks_err!("Check permission"))?;
 
         let km_dev = &self.keymint;
         match {
@@ -942,7 +928,7 @@
                     );
                     map_km_error(km_dev.upgradeKey(key_blob, &[]))
                 }
-                .context("In convert_storage_key_to_ephemeral: Failed to upgrade key blob.")?;
+                .context(ks_err!("Failed to upgrade key blob."))?;
                 let ephemeral_key = {
                     let _wp = self.watch_millis(
                         "In convert_storage_key_to_ephemeral: calling convertStorageKeyToEphemeral (2)",
@@ -950,8 +936,7 @@
                     );
                     map_km_error(km_dev.convertStorageKeyToEphemeral(&upgraded_blob))
                 }
-                    .context(concat!(
-                        "In convert_storage_key_to_ephemeral: ",
+                    .context(ks_err!(
                         "Failed to retrieve ephemeral key (after upgrade)."
                     ))?;
                 Ok(EphemeralStorageKeyResponse {
@@ -959,31 +944,30 @@
                     upgradedBlob: Some(upgraded_blob),
                 })
             }
-            Err(e) => Err(e)
-                .context("In convert_storage_key_to_ephemeral: Failed to retrieve ephemeral key."),
+            Err(e) => Err(e).context(ks_err!("Failed to retrieve ephemeral key.")),
         }
     }
 
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
         if key.domain != Domain::BLOB {
             return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
-                .context("In IKeystoreSecurityLevel delete_key: Key must be of Domain::BLOB");
+                .context(ks_err!("delete_key: Key must be of Domain::BLOB"));
         }
 
         let key_blob = key
             .blob
             .as_ref()
             .ok_or(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
-            .context("In IKeystoreSecurityLevel delete_key: No key blob specified")?;
+            .context(ks_err!("delete_key: No key blob specified"))?;
 
         check_key_permission(KeyPerm::Delete, key, &None)
-            .context("In IKeystoreSecurityLevel delete_key: Checking delete permissions")?;
+            .context(ks_err!("delete_key: Checking delete permissions"))?;
 
         let km_dev = &self.keymint;
         {
             let _wp =
                 self.watch_millis("In KeystoreSecuritylevel::delete_key: calling deleteKey", 500);
-            map_km_error(km_dev.deleteKey(key_blob)).context("In keymint device deleteKey")
+            map_km_error(km_dev.deleteKey(key_blob)).context(ks_err!("keymint device deleteKey"))
         }
     }
 }
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 8d2e5ad..a3e0fa5 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -18,6 +18,7 @@
 use std::collections::HashMap;
 
 use crate::audit_log::log_key_deleted;
+use crate::ks_err;
 use crate::permission::{KeyPerm, KeystorePerm};
 use crate::security_level::KeystoreSecurityLevel;
 use crate::utils::{
@@ -265,10 +266,12 @@
                 nspace: ThreadState::get_calling_uid() as u64 as i64,
                 ..Default::default()
             },
-            Domain::SELINUX => KeyDescriptor{domain, nspace: namespace, ..Default::default()},
-            _ => return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
-            ),
+            Domain::SELINUX => KeyDescriptor { domain, nspace: namespace, ..Default::default() },
+            _ => {
+                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!(
+                    "List entries is only supported for Domain::APP and Domain::SELINUX."
+                ))
+            }
         };
 
         // First we check if the caller has the info permission for the selected domain/namespace.
@@ -281,12 +284,12 @@
                 e.root_cause().downcast_ref::<selinux::Error>()
             {
                 check_keystore_permission(KeystorePerm::List)
-                    .context("In list_entries: While checking keystore permission.")?;
+                    .context(ks_err!("While checking keystore permission."))?;
                 if namespace != -1 {
                     k.nspace = namespace;
                 }
             } else {
-                return Err(e).context("In list_entries: While checking key permission.")?;
+                return Err(e).context(ks_err!("While checking key permission."))?;
             }
         }
 
@@ -305,7 +308,7 @@
                 })
             })
         })
-        .context("In delete_key: Trying to unbind the key.")?;
+        .context(ks_err!("Trying to unbind the key."))?;
         Ok(())
     }
 
@@ -330,7 +333,7 @@
                 )
             })
         })
-        .context("In KeystoreService::grant.")
+        .context(ks_err!("KeystoreService::grant."))
     }
 
     fn ungrant(&self, key: &KeyDescriptor, grantee_uid: i32) -> Result<()> {
@@ -339,7 +342,7 @@
                 check_key_permission(KeyPerm::Grant, k, &None)
             })
         })
-        .context("In KeystoreService::ungrant.")
+        .context(ks_err!("KeystoreService::ungrant."))
     }
 }
 
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 17d8914..175d8bb 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -18,11 +18,13 @@
 
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
-    ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+    ErrorCode::ErrorCode, KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
+    KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+    Tag::Tag,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
-    KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
+    Authorization::Authorization, Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
+    KeyDescriptor::KeyDescriptor, KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
 };
 
 use crate::authorizations::AuthSetBuilder;
@@ -59,6 +61,102 @@
     pub att_app_id: Option<Vec<u8>>,
 }
 
+/// DER-encoded PKCS#8 format RSA key. Generated using:
+/// openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1  "%02X" "\n"'
+pub static RSA_2048_KEY: &[u8] = &[
+    0x30, 0x82, 0x04, 0xBD, 0x02, 0x01, 0x00, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
+    0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x04, 0xA7, 0x30, 0x82, 0x04, 0xA3, 0x02, 0x01,
+    0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xE5, 0x14, 0xE3, 0xC2, 0x43, 0xF3, 0x0F, 0xCC, 0x22, 0x73,
+    0x9C, 0x84, 0xCC, 0x1B, 0x6C, 0x97, 0x4B, 0xC9, 0xDF, 0x1F, 0xE2, 0xB8, 0x80, 0x85, 0xF9, 0x27,
+    0xAB, 0x97, 0x94, 0x58, 0x4B, 0xC9, 0x40, 0x94, 0x5A, 0xB4, 0xD4, 0xF8, 0xD0, 0x36, 0xC4, 0x86,
+    0x17, 0x7D, 0xA2, 0x48, 0x6D, 0x40, 0xF0, 0xB9, 0x61, 0x4F, 0xCE, 0x65, 0x80, 0x88, 0x81, 0x59,
+    0x95, 0x11, 0x24, 0xF4, 0x36, 0xB7, 0xB7, 0x37, 0x44, 0xF4, 0x6C, 0x1C, 0xEB, 0x04, 0x19, 0x78,
+    0xB2, 0x29, 0x4D, 0x21, 0x44, 0x16, 0x57, 0x58, 0x6D, 0x7D, 0x56, 0xB5, 0x99, 0xDD, 0xD2, 0xAD,
+    0x02, 0x9A, 0x72, 0x16, 0x67, 0xD6, 0x00, 0x9F, 0x69, 0xE0, 0x25, 0xEE, 0x7C, 0x86, 0x54, 0x27,
+    0x4B, 0x50, 0xEF, 0x60, 0x52, 0x60, 0x82, 0xAA, 0x09, 0x15, 0x72, 0xD2, 0xEB, 0x01, 0x52, 0x04,
+    0x39, 0x60, 0xBC, 0x5E, 0x95, 0x07, 0xC8, 0xC2, 0x3A, 0x3A, 0xE2, 0xA4, 0x99, 0x6B, 0x27, 0xE3,
+    0xA3, 0x55, 0x69, 0xC4, 0xB3, 0x2D, 0x19, 0xC4, 0x34, 0x76, 0xFC, 0x27, 0xDA, 0x22, 0xB2, 0x62,
+    0x69, 0x25, 0xDE, 0x0D, 0xE7, 0x54, 0x3C, 0xBB, 0x61, 0xD2, 0x20, 0xDA, 0x7B, 0x6E, 0x63, 0xBD,
+    0x9A, 0x4B, 0xCD, 0x75, 0xC6, 0xA1, 0x5E, 0x1C, 0x3E, 0xD5, 0x63, 0x59, 0x22, 0x7E, 0xE0, 0x6C,
+    0x98, 0x25, 0x63, 0x97, 0x56, 0xDF, 0x71, 0xF5, 0x4C, 0x78, 0xE9, 0xE1, 0xD5, 0xFC, 0xF8, 0x5A,
+    0x5B, 0xF6, 0x1D, 0xFA, 0x5A, 0x99, 0x4C, 0x99, 0x19, 0x21, 0x1D, 0xF5, 0x24, 0x07, 0xEF, 0x8A,
+    0xC9, 0x9F, 0xE7, 0x3F, 0xBB, 0x46, 0x1A, 0x16, 0x96, 0xC6, 0xD6, 0x12, 0x7E, 0xDA, 0xCB, 0xEB,
+    0x2F, 0x1D, 0x3B, 0x31, 0xCC, 0x55, 0x63, 0xA2, 0x6F, 0x8A, 0xDE, 0x35, 0x52, 0x40, 0x04, 0xBF,
+    0xE0, 0x82, 0x32, 0xE1, 0x6D, 0x8B, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x2D,
+    0x1F, 0x71, 0x41, 0x79, 0xBA, 0xED, 0xD8, 0xAA, 0xCC, 0x94, 0xFE, 0xFF, 0x69, 0x43, 0x79, 0x85,
+    0xBF, 0x2C, 0xC9, 0x0E, 0x12, 0x83, 0x96, 0x60, 0x1E, 0x75, 0x49, 0x35, 0x3A, 0x33, 0x2B, 0x60,
+    0x22, 0x18, 0xBF, 0xD7, 0xD7, 0x6E, 0xC3, 0xEA, 0xEF, 0xF2, 0xBE, 0x97, 0x71, 0xA6, 0xBB, 0x8C,
+    0xEF, 0x27, 0x00, 0xDE, 0x49, 0xD6, 0x08, 0x8D, 0x5A, 0x04, 0xE7, 0xCC, 0x9C, 0xA2, 0x0E, 0x8B,
+    0xF3, 0x42, 0x0C, 0xD7, 0x22, 0xD7, 0x14, 0x06, 0xA4, 0x64, 0x8B, 0x88, 0x1A, 0xCE, 0x5B, 0x8C,
+    0x36, 0xE9, 0xD2, 0x2F, 0x7B, 0x33, 0xE4, 0xA2, 0xB3, 0xDB, 0x78, 0x6A, 0x92, 0x89, 0x3F, 0x78,
+    0xFD, 0xED, 0x8F, 0xEE, 0x48, 0xCC, 0x94, 0x75, 0x0D, 0x0C, 0x63, 0xD3, 0xD2, 0xE8, 0x47, 0x04,
+    0x55, 0xD3, 0xD6, 0x3A, 0xB8, 0xDA, 0xFB, 0x76, 0x99, 0x48, 0x68, 0x0A, 0x92, 0xA2, 0xCD, 0xF7,
+    0x45, 0x8B, 0x50, 0xFE, 0xF9, 0x1A, 0x33, 0x24, 0x3C, 0x2E, 0xDE, 0x88, 0xAD, 0xB2, 0x5B, 0x9F,
+    0x44, 0xEA, 0xD1, 0x9F, 0xC7, 0x9F, 0x02, 0x5E, 0x31, 0x61, 0xB3, 0xD6, 0xE2, 0xE1, 0xBC, 0xFB,
+    0x1C, 0xDB, 0xBD, 0xB2, 0x9A, 0xE5, 0xEF, 0xDA, 0xCD, 0x29, 0xA5, 0x45, 0xCC, 0x67, 0x01, 0x8B,
+    0x1C, 0x1D, 0x0E, 0x8F, 0x73, 0x69, 0x4D, 0x4D, 0xF6, 0x9D, 0xA6, 0x6C, 0x9A, 0x1C, 0xF4, 0x5C,
+    0xE4, 0x83, 0x9A, 0x77, 0x12, 0x01, 0xBD, 0xCE, 0x66, 0x3A, 0x4B, 0x3D, 0x6E, 0xE0, 0x6E, 0x82,
+    0x98, 0xDE, 0x74, 0x11, 0x47, 0xEC, 0x7A, 0x3A, 0xA9, 0xD8, 0x48, 0x00, 0x26, 0x64, 0x47, 0x7B,
+    0xAE, 0x55, 0x9D, 0x29, 0x22, 0xB4, 0xB3, 0xB9, 0xB1, 0x64, 0xEA, 0x3B, 0x5A, 0xD3, 0x3F, 0x8D,
+    0x0F, 0x14, 0x7E, 0x4E, 0xB8, 0x1B, 0x06, 0xFC, 0xB1, 0x7E, 0xCD, 0xB9, 0x1A, 0x4E, 0xA1, 0x02,
+    0x81, 0x81, 0x00, 0xF9, 0xDE, 0xEE, 0xED, 0x13, 0x2F, 0xBB, 0xE7, 0xE2, 0xB3, 0x2D, 0x98, 0xD2,
+    0xE8, 0x25, 0x07, 0x5A, 0x1E, 0x51, 0x0A, 0xC8, 0xAD, 0x50, 0x4B, 0x80, 0xC6, 0x22, 0xF5, 0x9B,
+    0x08, 0xE6, 0x3D, 0x01, 0xC6, 0x3E, 0xC8, 0xD2, 0x54, 0x9F, 0x91, 0x77, 0x95, 0xCD, 0xCA, 0xC7,
+    0xE7, 0x47, 0x94, 0xA9, 0x5F, 0x4E, 0xBE, 0x31, 0x3D, 0xB4, 0xAF, 0x43, 0x0F, 0xDC, 0x8D, 0x9C,
+    0x1E, 0x52, 0x7B, 0x72, 0x21, 0x34, 0xB3, 0x96, 0x7C, 0x9C, 0xB8, 0x51, 0x65, 0x60, 0xAC, 0x3D,
+    0x11, 0x32, 0xB8, 0xD6, 0x34, 0x35, 0x66, 0xD0, 0x30, 0xB9, 0xE9, 0x67, 0x2C, 0x87, 0x73, 0x43,
+    0x9C, 0x12, 0x16, 0x7D, 0x4A, 0xD9, 0xA3, 0x4C, 0x24, 0x64, 0x6A, 0x32, 0x8E, 0xC3, 0xD8, 0x00,
+    0x90, 0x5C, 0x4D, 0x65, 0x01, 0x53, 0x8A, 0xD0, 0x87, 0xCE, 0x96, 0xEF, 0xFA, 0x73, 0x03, 0xF1,
+    0xDC, 0x1B, 0x9B, 0x02, 0x81, 0x81, 0x00, 0xEA, 0xB3, 0x69, 0x00, 0x11, 0x0E, 0x50, 0xAA, 0xD3,
+    0x22, 0x51, 0x78, 0x9D, 0xFF, 0x05, 0x62, 0xBC, 0x9A, 0x67, 0x86, 0xE1, 0xC5, 0x02, 0x2D, 0x14,
+    0x11, 0x29, 0x30, 0xE7, 0x90, 0x5D, 0x72, 0x6F, 0xC5, 0x62, 0xEB, 0xD4, 0xB0, 0x3F, 0x3D, 0xDC,
+    0xB9, 0xFC, 0x2B, 0x5C, 0xBD, 0x9E, 0x71, 0x81, 0x5C, 0xC5, 0xFE, 0xDF, 0x69, 0x73, 0x12, 0x66,
+    0x92, 0x06, 0xD4, 0xD5, 0x8F, 0xDF, 0x14, 0x2E, 0x9C, 0xD0, 0x4C, 0xC2, 0x4D, 0x31, 0x2E, 0x47,
+    0xA5, 0xDC, 0x8A, 0x83, 0x7B, 0xE8, 0xA5, 0xC3, 0x03, 0x98, 0xD8, 0xBF, 0xF4, 0x7D, 0x6E, 0x87,
+    0x55, 0xE4, 0x0F, 0x15, 0x10, 0xC8, 0x76, 0x4F, 0xAD, 0x1D, 0x1C, 0x95, 0x41, 0x9D, 0x88, 0xEC,
+    0x8C, 0xDA, 0xBA, 0x90, 0x7F, 0x8D, 0xD9, 0x8B, 0x47, 0x6C, 0x0C, 0xFF, 0xBA, 0x73, 0x00, 0x20,
+    0x1F, 0xF7, 0x7E, 0x5F, 0xF4, 0xEC, 0xD1, 0x02, 0x81, 0x80, 0x16, 0xB7, 0x43, 0xB5, 0x5D, 0xD7,
+    0x2B, 0x18, 0x0B, 0xAE, 0x0A, 0x69, 0x28, 0x53, 0x5E, 0x7A, 0x6A, 0xA0, 0xF2, 0xF1, 0x2E, 0x09,
+    0x43, 0x91, 0x79, 0xA5, 0x89, 0xAC, 0x16, 0x6A, 0x1A, 0xB4, 0x55, 0x22, 0xF6, 0xB6, 0x3F, 0x18,
+    0xDE, 0x60, 0xD5, 0x24, 0x53, 0x4F, 0x2A, 0x19, 0x46, 0x92, 0xA7, 0x4B, 0x38, 0xD7, 0x65, 0x96,
+    0x9C, 0x84, 0x8A, 0x6E, 0x38, 0xB8, 0xCF, 0x06, 0x9A, 0xAD, 0x0A, 0x55, 0x26, 0x7B, 0x65, 0x24,
+    0xF3, 0x02, 0x76, 0xB3, 0xE6, 0xB4, 0x01, 0xE1, 0x3C, 0x61, 0x3D, 0x68, 0x05, 0xAA, 0xD1, 0x26,
+    0x7C, 0xE0, 0x51, 0x36, 0xE5, 0x21, 0x7F, 0x76, 0x02, 0xD6, 0xF4, 0x91, 0x07, 0x74, 0x27, 0x09,
+    0xEF, 0xEF, 0x0F, 0xA5, 0x96, 0xFC, 0x5E, 0x20, 0xC1, 0xA3, 0x6F, 0x99, 0x4D, 0x45, 0x03, 0x6C,
+    0x35, 0x45, 0xD7, 0x8F, 0x47, 0x41, 0x86, 0x8D, 0x62, 0x1D, 0x02, 0x81, 0x81, 0x00, 0xC3, 0x93,
+    0x85, 0xA7, 0xFC, 0x8E, 0x85, 0x42, 0x14, 0x76, 0xC0, 0x95, 0x56, 0x73, 0xB0, 0xB5, 0x3A, 0x9D,
+    0x20, 0x30, 0x11, 0xEA, 0xED, 0x89, 0x4A, 0xF3, 0x91, 0xF3, 0xA2, 0xC3, 0x76, 0x5B, 0x6A, 0x30,
+    0x7D, 0xE2, 0x2F, 0x76, 0x3E, 0xFC, 0xF9, 0xF6, 0x31, 0xE0, 0xA0, 0x83, 0x92, 0x88, 0xDB, 0x57,
+    0xC7, 0xD6, 0x3F, 0xAD, 0xCB, 0xAA, 0x45, 0xB6, 0xE1, 0xE2, 0x71, 0xA4, 0x56, 0x2C, 0xA7, 0x3B,
+    0x1D, 0x89, 0x19, 0x50, 0xE1, 0xEE, 0xC2, 0xDD, 0xC0, 0x0D, 0xDC, 0xCB, 0x60, 0x6E, 0xE1, 0x37,
+    0x1A, 0x23, 0x64, 0xB2, 0x03, 0xE4, 0x1A, 0xFA, 0xC3, 0xF4, 0x9D, 0x85, 0x42, 0xC6, 0xF4, 0x56,
+    0x39, 0xB0, 0x1B, 0xE0, 0x75, 0xBA, 0x28, 0x04, 0xA8, 0x30, 0x57, 0x41, 0x33, 0x9F, 0x58, 0xA4,
+    0xC7, 0xB1, 0x7D, 0x58, 0x8D, 0x84, 0x49, 0x40, 0xDA, 0x28, 0x81, 0x25, 0xC4, 0x41, 0x02, 0x81,
+    0x80, 0x13, 0x20, 0x65, 0xD5, 0x96, 0x98, 0x8D, 0x16, 0x73, 0xA1, 0x31, 0x73, 0x79, 0xBA, 0xEC,
+    0xB0, 0xD9, 0x0C, 0xF6, 0xEF, 0x2F, 0xC2, 0xE7, 0x96, 0x9B, 0xA1, 0x2D, 0xE9, 0xFB, 0x45, 0xB9,
+    0xD0, 0x30, 0xE2, 0xBD, 0x30, 0x4F, 0xB6, 0xFE, 0x24, 0x02, 0xCF, 0x8D, 0x51, 0x48, 0x45, 0xD9,
+    0xF7, 0x20, 0x53, 0x1C, 0x0B, 0xA9, 0x7E, 0xC2, 0xA2, 0x65, 0xCC, 0x3E, 0x0E, 0x0D, 0xF1, 0x62,
+    0xDD, 0x5F, 0xBC, 0x55, 0x9B, 0x58, 0x26, 0x40, 0x6A, 0xEE, 0x02, 0x55, 0x36, 0xE9, 0xBA, 0x82,
+    0x5A, 0xFD, 0x3C, 0xDF, 0xA6, 0x26, 0x32, 0x81, 0xA9, 0x5E, 0x46, 0xBE, 0xBA, 0xDC, 0xD3, 0x2A,
+    0x3A, 0x3B, 0xC1, 0x4E, 0xF7, 0x1A, 0xDC, 0x4B, 0xAF, 0x67, 0x1B, 0x3A, 0x83, 0x0D, 0x04, 0xDE,
+    0x27, 0x47, 0xFC, 0xE6, 0x39, 0x89, 0x7B, 0x66, 0xF9, 0x50, 0x4D, 0xF1, 0xAC, 0x20, 0x43, 0x7E,
+    0xEE,
+];
+
+/// DER-encoded PKCS#8 format EC key. Generated using:
+/// openssl ecparam -name prime256v1 -genkey | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1  "%02X" "\n"'
+pub static EC_P_256_KEY: &[u8] = &[
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,
+    0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02,
+    0x01, 0x01, 0x04, 0x20, 0xB9, 0x1D, 0xAF, 0x50, 0xFD, 0xD8, 0x6A, 0x40, 0xAB, 0x2C, 0xCB, 0x54,
+    0x4E, 0xED, 0xF1, 0x64, 0xBC, 0x30, 0x25, 0xFB, 0xC4, 0x69, 0x00, 0x34, 0x1A, 0x82, 0xA3, 0x72,
+    0x5D, 0xC7, 0xA9, 0x85, 0xA1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xE8, 0x53, 0x0A, 0xF2, 0xD3, 0x68,
+    0x40, 0x48, 0x8C, 0xB4, 0x2F, 0x11, 0x34, 0xD7, 0xF4, 0x4A, 0x5C, 0x33, 0xFF, 0xF6, 0x2B, 0xF7,
+    0x98, 0x0F, 0x02, 0xA5, 0xD7, 0x4F, 0xF9, 0xDE, 0x60, 0x9C, 0x6E, 0xB0, 0x45, 0xDA, 0x3F, 0xF4,
+    0x34, 0x23, 0x9B, 0x4C, 0x3A, 0x09, 0x9C, 0x5E, 0x5D, 0x37, 0x96, 0xAC, 0x4A, 0xE7, 0x65, 0x2B,
+    0xD6, 0x84, 0x98, 0xEA, 0x96, 0x91, 0xFB, 0x78, 0xED, 0x86,
+];
+
 /// To map Keystore errors.
 #[derive(thiserror::Error, Debug, Eq, PartialEq)]
 pub enum Error {
@@ -71,6 +169,9 @@
     /// Exception
     #[error("Binder exception {0:?}")]
     Binder(ExceptionCode),
+    /// This is returned if the C implementation of extractSubjectFromCertificate failed.
+    #[error("Failed to validate certificate chain.")]
+    ValidateCertChainFailed,
 }
 
 /// Keystore2 error mapping.
@@ -112,6 +213,7 @@
 ) -> binder::Result<KeyMetadata> {
     let mut key_attest = false;
     let mut gen_params = AuthSetBuilder::new()
+        .no_auth_required()
         .algorithm(Algorithm::EC)
         .purpose(KeyPurpose::SIGN)
         .purpose(KeyPurpose::VERIFY)
@@ -151,8 +253,8 @@
 }
 
 /// Generate EC signing key.
-pub fn generate_ec_key<S: IKeystoreSecurityLevel + ?Sized>(
-    sec_level: &S,
+pub fn generate_ec_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
     domain: Domain,
     nspace: i64,
     alias: Option<String>,
@@ -336,3 +438,401 @@
 
     Ok(key_metadata)
 }
+
+/// Generate RSA or EC attestation keys using below parameters -
+///     Purpose: ATTEST_KEY
+///     Digest: Digest::SHA_2_256
+///     Padding: PaddingMode::RSA_PKCS1_1_5_SIGN
+///     RSA-Key-Size: 2048
+///     EC-Curve: EcCurve::P_256
+pub fn generate_attestation_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    algorithm: Algorithm,
+    att_challenge: &[u8],
+    att_app_id: &[u8],
+) -> binder::Result<KeyMetadata> {
+    assert!(algorithm == Algorithm::RSA || algorithm == Algorithm::EC);
+
+    if algorithm == Algorithm::RSA {
+        let alias = "ks_rsa_attest_test_key";
+        let metadata = generate_rsa_key(
+            sec_level,
+            Domain::APP,
+            -1,
+            Some(alias.to_string()),
+            &KeyParams {
+                key_size: 2048,
+                purpose: vec![KeyPurpose::ATTEST_KEY],
+                padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+                digest: Some(Digest::SHA_2_256),
+                mgf_digest: None,
+                block_mode: None,
+                att_challenge: Some(att_challenge.to_vec()),
+                att_app_id: Some(att_app_id.to_vec()),
+            },
+            None,
+        )
+        .unwrap();
+        Ok(metadata)
+    } else {
+        let metadata = generate_ec_attestation_key(
+            sec_level,
+            att_challenge,
+            att_app_id,
+            Digest::SHA_2_256,
+            EcCurve::P_256,
+        )
+        .unwrap();
+
+        Ok(metadata)
+    }
+}
+
+/// Generate EC attestation key with the given
+///    curve, attestation-challenge and attestation-app-id.
+pub fn generate_ec_attestation_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    att_challenge: &[u8],
+    att_app_id: &[u8],
+    digest: Digest,
+    ec_curve: EcCurve,
+) -> binder::Result<KeyMetadata> {
+    let alias = "ks_attest_ec_test_key";
+    let gen_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::ATTEST_KEY)
+        .ec_curve(ec_curve)
+        .digest(digest)
+        .attestation_challenge(att_challenge.to_vec())
+        .attestation_app_id(att_app_id.to_vec());
+
+    let attestation_key_metadata = sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        None,
+        &gen_params,
+        0,
+        b"entropy",
+    )?;
+
+    // Should have public certificate.
+    assert!(attestation_key_metadata.certificate.is_some());
+    // Should have an attestation record.
+    assert!(attestation_key_metadata.certificateChain.is_some());
+
+    Ok(attestation_key_metadata)
+}
+
+/// Generate EC-P-256 key and attest it with given attestation key.
+pub fn generate_ec_256_attested_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: Option<String>,
+    att_challenge: &[u8],
+    att_app_id: &[u8],
+    attest_key: &KeyDescriptor,
+) -> binder::Result<KeyMetadata> {
+    let ec_gen_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(att_challenge.to_vec())
+        .attestation_app_id(att_app_id.to_vec());
+
+    let ec_key_metadata = sec_level
+        .generateKey(
+            &KeyDescriptor { domain: Domain::APP, nspace: -1, alias, blob: None },
+            Some(attest_key),
+            &ec_gen_params,
+            0,
+            b"entropy",
+        )
+        .unwrap();
+
+    // Should have public certificate.
+    assert!(ec_key_metadata.certificate.is_some());
+    // Shouldn't have an attestation record.
+    assert!(ec_key_metadata.certificateChain.is_none());
+
+    Ok(ec_key_metadata)
+}
+
+fn check_key_param(authorizations: &[Authorization], key_param: KeyParameter) -> bool {
+    for authrization in authorizations {
+        if authrization.keyParameter == key_param {
+            return true;
+        }
+    }
+
+    false
+}
+
+/// Imports above defined RSA key - `RSA_2048_KEY` and validates imported key parameters.
+pub fn import_rsa_2048_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+    import_params: AuthSetBuilder,
+) -> binder::Result<KeyMetadata> {
+    let key_metadata = sec_level
+        .importKey(
+            &KeyDescriptor { domain, nspace, alias, blob: None },
+            None,
+            &import_params,
+            0,
+            RSA_2048_KEY,
+        )
+        .unwrap();
+
+    assert!(key_metadata.certificate.is_some());
+    assert!(key_metadata.certificateChain.is_none());
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::RSA) }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(2048) }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter {
+            tag: Tag::RSA_PUBLIC_EXPONENT,
+            value: KeyParameterValue::LongInteger(65537)
+        }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter {
+            tag: Tag::PADDING,
+            value: KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS)
+        }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+    ));
+
+    Ok(key_metadata)
+}
+
+/// Imports above defined EC key - `EC_P_256_KEY` and validates imported key parameters.
+pub fn import_ec_p_256_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+    import_params: AuthSetBuilder,
+) -> binder::Result<KeyMetadata> {
+    let key_metadata = sec_level
+        .importKey(
+            &KeyDescriptor { domain, nspace, alias, blob: None },
+            None,
+            &import_params,
+            0,
+            EC_P_256_KEY,
+        )
+        .unwrap();
+
+    assert!(key_metadata.certificate.is_some());
+    assert!(key_metadata.certificateChain.is_none());
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::EC) }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::EC_CURVE, value: KeyParameterValue::EcCurve(EcCurve::P_256) }
+    ));
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+    ));
+
+    Ok(key_metadata)
+}
+
+/// Import sample AES key and validate its key parameters.
+pub fn import_aes_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+) -> binder::Result<KeyMetadata> {
+    static AES_KEY: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+    let key_size = AES_KEY.len() * 8;
+
+    let import_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::AES)
+        .block_mode(BlockMode::ECB)
+        .key_size(key_size.try_into().unwrap())
+        .purpose(KeyPurpose::ENCRYPT)
+        .purpose(KeyPurpose::DECRYPT)
+        .padding_mode(PaddingMode::PKCS7);
+
+    let key_metadata = sec_level.importKey(
+        &KeyDescriptor { domain, nspace, alias, blob: None },
+        None,
+        &import_params,
+        0,
+        AES_KEY,
+    )?;
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::AES) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter {
+            tag: Tag::PADDING,
+            value: KeyParameterValue::PaddingMode(PaddingMode::PKCS7)
+        }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(BlockMode::ECB) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+    ));
+
+    Ok(key_metadata)
+}
+
+/// Import sample 3DES key and validate its key parameters.
+pub fn import_3des_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+) -> binder::Result<KeyMetadata> {
+    static TRIPLE_DES_KEY: &[u8] = &[
+        0xa4, 0x9d, 0x75, 0x64, 0x19, 0x9e, 0x97, 0xcb, 0x52, 0x9d, 0x2c, 0x9d, 0x97, 0xbf, 0x2f,
+        0x98, 0xd3, 0x5e, 0xdf, 0x57, 0xba, 0x1f, 0x73, 0x58,
+    ];
+
+    let import_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::TRIPLE_DES)
+        .block_mode(BlockMode::ECB)
+        .key_size(168)
+        .purpose(KeyPurpose::ENCRYPT)
+        .purpose(KeyPurpose::DECRYPT)
+        .padding_mode(PaddingMode::PKCS7);
+
+    let key_metadata = sec_level.importKey(
+        &KeyDescriptor { domain, nspace, alias, blob: None },
+        None,
+        &import_params,
+        0,
+        TRIPLE_DES_KEY,
+    )?;
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter {
+            tag: Tag::ALGORITHM,
+            value: KeyParameterValue::Algorithm(Algorithm::TRIPLE_DES)
+        }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(168) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter {
+            tag: Tag::PADDING,
+            value: KeyParameterValue::PaddingMode(PaddingMode::PKCS7)
+        }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(BlockMode::ECB) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+    ));
+
+    Ok(key_metadata)
+}
+
+/// Import sample HMAC key and validate its key parameters.
+pub fn import_hmac_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+) -> binder::Result<KeyMetadata> {
+    static HMAC_KEY: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+    let key_size = HMAC_KEY.len() * 8;
+
+    let import_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::HMAC)
+        .key_size(key_size.try_into().unwrap())
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .min_mac_length(256);
+
+    let key_metadata = sec_level.importKey(
+        &KeyDescriptor { domain, nspace, alias, blob: None },
+        None,
+        &import_params,
+        0,
+        HMAC_KEY,
+    )?;
+
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::HMAC) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
+    ));
+    assert!(check_key_param(
+        &key_metadata.authorizations,
+        KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+    ));
+
+    Ok(key_metadata)
+}
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index e5d78e4..dd5d782 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -36,6 +36,7 @@
     rustlibs: [
         "librustutils",
         "libkeystore2_test_utils",
+	"packagemanager_aidl-rust",
         "libnix",
         "libanyhow",
         "libbinder_rs",
@@ -43,6 +44,40 @@
         "liblibc",
         "libserde",
         "libthiserror",
+	"libcxx",
+	"libopenssl",
+    ],
+    static_libs: [
+        "libkeystore2_ffi_test_utils",
+        "libgtest",
+        "libkeymint_vts_test_utils",
+    ],
+    shared_libs: [
+        "libcrypto",
     ],
     require_root: true,
 }
+
+cc_library_static {
+    name: "libkeystore2_ffi_test_utils",
+    srcs: ["ffi_test_utils.cpp"],
+    defaults: [
+        "keymint_vts_defaults",
+        "hidl_defaults",
+    ],
+    generated_headers: [
+        "cxx-bridge-header",
+    ],
+    generated_sources: ["libkeystore2_ffi_test_utils_bridge_code"],
+    static_libs: [
+        "libkeymint_vts_test_utils",
+    ],
+}
+
+genrule {
+    name: "libkeystore2_ffi_test_utils_bridge_code",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) >> $(out)",
+    srcs: ["keystore2_client_attest_key_tests.rs"],
+    out: ["libkeystore2_test_utils_cxx_generated.cc"],
+}
diff --git a/keystore2/tests/ffi_test_utils.cpp b/keystore2/tests/ffi_test_utils.cpp
new file mode 100644
index 0000000..fb5a7d2
--- /dev/null
+++ b/keystore2/tests/ffi_test_utils.cpp
@@ -0,0 +1,120 @@
+#include "ffi_test_utils.hpp"
+
+#include <iostream>
+
+#include <KeyMintAidlTestBase.h>
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <vector>
+
+using aidl::android::hardware::security::keymint::ErrorCode;
+
+#define TAG_SEQUENCE 0x30
+#define LENGTH_MASK 0x80
+#define LENGTH_VALUE_MASK 0x7F
+
+/* This function extracts a certificate from the certs_chain_buffer at the given
+ * offset. Each DER encoded certificate starts with TAG_SEQUENCE followed by the
+ * total length of the certificate. The length of the certificate is determined
+ * as per ASN.1 encoding rules for the length octets.
+ *
+ * @param certs_chain_buffer: buffer containing DER encoded X.509 certificates
+ *                            arranged sequentially.
+ * @data_size: Length of the DER encoded X.509 certificates buffer.
+ * @index: DER encoded X.509 certificates buffer offset.
+ * @cert: Encoded certificate to be extracted from buffer as outcome.
+ * @return: ErrorCode::OK on success, otherwise ErrorCode::UNKNOWN_ERROR.
+ */
+ErrorCode
+extractCertFromCertChainBuffer(uint8_t* certs_chain_buffer, int certs_chain_buffer_size, int& index,
+                               aidl::android::hardware::security::keymint::Certificate& cert) {
+    if (index >= certs_chain_buffer_size) {
+        return ErrorCode::UNKNOWN_ERROR;
+    }
+
+    uint32_t length = 0;
+    std::vector<uint8_t> cert_bytes;
+    if (certs_chain_buffer[index] == TAG_SEQUENCE) {
+        // Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
+        if (0 == (certs_chain_buffer[index + 1] & LENGTH_MASK)) {
+            length = (uint32_t)certs_chain_buffer[index];
+            // Add SEQ and Length fields
+            length += 2;
+        } else {
+            // Long form. Two to 127 octets. Bit 8 of first octet has value "1" and
+            // bits 7-1 give the number of additional length octets. Second and following
+            // octets give the actual length.
+            int additionalBytes = certs_chain_buffer[index + 1] & LENGTH_VALUE_MASK;
+            if (additionalBytes == 0x01) {
+                length = certs_chain_buffer[index + 2];
+                // Add SEQ and Length fields
+                length += 3;
+            } else if (additionalBytes == 0x02) {
+                length = (certs_chain_buffer[index + 2] << 8 | certs_chain_buffer[index + 3]);
+                // Add SEQ and Length fields
+                length += 4;
+            } else if (additionalBytes == 0x04) {
+                length = certs_chain_buffer[index + 2] << 24;
+                length |= certs_chain_buffer[index + 3] << 16;
+                length |= certs_chain_buffer[index + 4] << 8;
+                length |= certs_chain_buffer[index + 5];
+                // Add SEQ and Length fields
+                length += 6;
+            } else {
+                // Length is larger than uint32_t max limit.
+                return ErrorCode::UNKNOWN_ERROR;
+            }
+        }
+        cert_bytes.insert(cert_bytes.end(), (certs_chain_buffer + index),
+                          (certs_chain_buffer + index + length));
+        index += length;
+
+        for (int i = 0; i < cert_bytes.size(); i++) {
+            cert.encodedCertificate = std::move(cert_bytes);
+        }
+    } else {
+        // SEQUENCE TAG MISSING.
+        return ErrorCode::UNKNOWN_ERROR;
+    }
+
+    return ErrorCode::OK;
+}
+
+ErrorCode getCertificateChain(
+    rust::Vec<rust::u8>& chainBuffer,
+    std::vector<aidl::android::hardware::security::keymint::Certificate>& certChain) {
+    uint8_t* data = chainBuffer.data();
+    int index = 0;
+    int data_size = chainBuffer.size();
+
+    while (index < data_size) {
+        aidl::android::hardware::security::keymint::Certificate cert =
+            aidl::android::hardware::security::keymint::Certificate();
+        if (extractCertFromCertChainBuffer(data, data_size, index, cert) != ErrorCode::OK) {
+            return ErrorCode::UNKNOWN_ERROR;
+        }
+        certChain.push_back(std::move(cert));
+    }
+    return ErrorCode::OK;
+}
+
+bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check) {
+    std::vector<aidl::android::hardware::security::keymint::Certificate> cert_chain =
+        std::vector<aidl::android::hardware::security::keymint::Certificate>();
+    if (cert_len <= 0) {
+        return false;
+    }
+    if (getCertificateChain(cert_buf, cert_chain) != ErrorCode::OK) {
+        return false;
+    }
+
+    for (int i = 0; i < cert_chain.size(); i++) {
+        std::cout << cert_chain[i].toString() << "\n";
+    }
+    auto result = aidl::android::hardware::security::keymint::test::ChainSignaturesAreValid(
+        cert_chain, strict_issuer_check);
+
+    if (result == testing::AssertionSuccess()) return true;
+
+    return false;
+}
diff --git a/keystore2/tests/ffi_test_utils.hpp b/keystore2/tests/ffi_test_utils.hpp
new file mode 100644
index 0000000..7f5c3b2
--- /dev/null
+++ b/keystore2/tests/ffi_test_utils.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "rust/cxx.h"
+
+bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check);
diff --git a/keystore2/tests/keystore2_client_aes_key_tests.rs b/keystore2/tests/keystore2_client_aes_key_tests.rs
index c56eef6..885cbf5 100644
--- a/keystore2/tests/keystore2_client_aes_key_tests.rs
+++ b/keystore2/tests/keystore2_client_aes_key_tests.rs
@@ -26,7 +26,8 @@
 };
 
 use crate::keystore2_client_test_utils::{
-    perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
+    has_trusty_keymint, perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op,
+    SAMPLE_PLAIN_TEXT,
 };
 
 /// Generate a AES key. Create encrypt and decrypt operations using the generated key.
@@ -391,7 +392,12 @@
         &mut None,
     ));
     assert!(result.is_err());
-    assert_eq!(Error::Km(ErrorCode::MISSING_MAC_LENGTH), result.unwrap_err());
+
+    if has_trusty_keymint() {
+        assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::MISSING_MAC_LENGTH));
+    } else {
+        assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH));
+    }
 }
 
 /// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
new file mode 100644
index 0000000..fc3148c
--- /dev/null
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -0,0 +1,526 @@
+// 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.
+
+use nix::unistd::getuid;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+    ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+    SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{
+    authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use crate::{
+    keystore2_client_test_utils::app_attest_key_feature_exists,
+    skip_test_if_no_app_attest_key_feature,
+};
+
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        include!("ffi_test_utils.hpp");
+        fn validateCertChain(cert_buf: Vec<u8>, cert_len: u32, strict_issuer_check: bool) -> bool;
+    }
+}
+
+/// Validate given certificate chain.
+pub fn validate_certchain(cert_buf: &[u8]) -> Result<bool, Error> {
+    if ffi::validateCertChain(cert_buf.to_vec(), cert_buf.len().try_into().unwrap(), true) {
+        return Ok(true);
+    }
+
+    Err(Error::ValidateCertChainFailed)
+}
+
+/// Generate RSA and EC attestation keys and use them for signing RSA-signing keys.
+/// Test should be able to generate attestation keys and use them successfully.
+#[test]
+fn keystore2_attest_rsa_signing_key_success() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    for algo in [Algorithm::RSA, Algorithm::EC] {
+        // Create attestation key.
+        let attestation_key_metadata =
+            key_generations::generate_attestation_key(&sec_level, algo, att_challenge, att_app_id)
+                .unwrap();
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+        validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+
+        // Create RSA signing key and use attestation key to sign it.
+        let sign_key_alias = format!("ks_attest_rsa_signing_key_{}", getuid());
+        let sign_key_metadata = key_generations::generate_rsa_key(
+            &sec_level,
+            Domain::APP,
+            -1,
+            Some(sign_key_alias),
+            &key_generations::KeyParams {
+                key_size: 2048,
+                purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+                padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+                digest: Some(Digest::SHA_2_256),
+                mgf_digest: None,
+                block_mode: None,
+                att_challenge: Some(att_challenge.to_vec()),
+                att_app_id: Some(att_app_id.to_vec()),
+            },
+            Some(&attestation_key_metadata.key),
+        )
+        .unwrap();
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(sign_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+        validate_certchain(&cert_chain).expect("Error while validating cert chain");
+    }
+}
+
+/// Generate RSA and EC attestation keys and use them for signing RSA encrypt/decrypt keys.
+/// Test should be able to generate attestation keys and use them successfully.
+#[test]
+fn keystore2_attest_rsa_encrypt_key_success() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    for algo in [Algorithm::RSA, Algorithm::EC] {
+        // Create attestation key.
+        let attestation_key_metadata =
+            key_generations::generate_attestation_key(&sec_level, algo, att_challenge, att_app_id)
+                .unwrap();
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+        validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+
+        // Create RSA encrypt/decrypt key and use attestation key to sign it.
+        let decrypt_key_alias = format!("ks_attest_rsa_encrypt_key_{}", getuid());
+        let decrypt_key_metadata = key_generations::generate_rsa_key(
+            &sec_level,
+            Domain::APP,
+            -1,
+            Some(decrypt_key_alias),
+            &key_generations::KeyParams {
+                key_size: 2048,
+                purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+                padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
+                digest: Some(Digest::SHA_2_256),
+                mgf_digest: None,
+                block_mode: None,
+                att_challenge: Some(att_challenge.to_vec()),
+                att_app_id: Some(att_app_id.to_vec()),
+            },
+            Some(&attestation_key_metadata.key),
+        )
+        .unwrap();
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(decrypt_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+
+        validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+    }
+}
+
+/// Generate RSA and EC attestation keys and use them for signing EC keys.
+/// Test should be able to generate attestation keys and use them successfully.
+#[test]
+fn keystore2_attest_ec_key_success() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    for algo in [Algorithm::RSA, Algorithm::EC] {
+        // Create attestation key.
+        let attestation_key_metadata =
+            key_generations::generate_attestation_key(&sec_level, algo, att_challenge, att_app_id)
+                .unwrap();
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+        validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+
+        // Create EC key and use attestation key to sign it.
+        let ec_key_alias = format!("ks_ec_attested_test_key_{}", getuid());
+        let ec_key_metadata = key_generations::generate_ec_256_attested_key(
+            &sec_level,
+            Some(ec_key_alias),
+            att_challenge,
+            att_app_id,
+            &attestation_key_metadata.key,
+        )
+        .unwrap();
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(ec_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+
+        validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+    }
+}
+
+/// Generate EC-CURVE_25519 attestation key and use it for signing RSA-signing keys.
+/// Test should be able to generate RSA signing key with EC-CURVE_25519 as attestation key
+/// successfully.
+#[test]
+fn keystore2_attest_rsa_signing_key_with_ec_25519_key_success() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    // Create EcCurve::CURVE_25519 attestation key.
+    let attestation_key_metadata = key_generations::generate_ec_attestation_key(
+        &sec_level,
+        att_challenge,
+        att_app_id,
+        Digest::NONE,
+        EcCurve::CURVE_25519,
+    )
+    .unwrap();
+
+    let mut cert_chain: Vec<u8> = Vec::new();
+    cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+    cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+    validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+
+    // Create RSA signing key and use attestation key to sign it.
+    let sign_key_alias = format!("ksrsa_attested_sign_test_key_{}", getuid());
+    let sign_key_metadata = key_generations::generate_rsa_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(sign_key_alias),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+            digest: Some(Digest::SHA_2_256),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: Some(att_challenge.to_vec()),
+            att_app_id: Some(att_app_id.to_vec()),
+        },
+        Some(&attestation_key_metadata.key),
+    )
+    .unwrap();
+
+    let mut cert_chain: Vec<u8> = Vec::new();
+    cert_chain.extend(sign_key_metadata.certificate.as_ref().unwrap());
+    cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+    cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+    validate_certchain(&cert_chain).expect("Error while validating cert chain");
+}
+
+/// Try to generate RSA attestation key with multiple purposes. Test should fail with error code
+/// `INCOMPATIBLE_PURPOSE` to generate an attestation key.
+#[test]
+fn keystore2_generate_rsa_attest_key_with_multi_purpose_fail() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let digest = Digest::SHA_2_256;
+    let padding = PaddingMode::RSA_PKCS1_1_5_SIGN;
+    let key_size = 2048;
+
+    let attest_key_alias =
+        format!("ksrsa_attest_multipurpose_key_{}{}{}", getuid(), key_size, digest.0);
+
+    let attest_gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .purpose(KeyPurpose::ATTEST_KEY)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(digest)
+        .key_size(key_size)
+        .rsa_public_exponent(65537)
+        .padding_mode(padding);
+
+    let result = key_generations::map_ks_error(sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(attest_key_alias),
+            blob: None,
+        },
+        None,
+        &attest_gen_params,
+        0,
+        b"entropy",
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Try to generate EC attestation key with multiple purposes. Test should fail with error code
+/// `INCOMPATIBLE_PURPOSE` to generate an attestation key.
+#[test]
+fn keystore2_ec_attest_key_with_multi_purpose_fail() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let attest_key_alias = format!("ks_ec_attest_multipurpose_key_{}", getuid());
+
+    let attest_gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::ATTEST_KEY)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256);
+
+    let result = key_generations::map_ks_error(sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(attest_key_alias),
+            blob: None,
+        },
+        None,
+        &attest_gen_params,
+        0,
+        b"entropy",
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Generate RSA attestation key and try to use it for signing RSA key without providing
+/// attestation challenge. Test should fail to generate a key with error code
+/// `ATTESTATION_CHALLENGE_MISSING`.
+#[test]
+fn keystore2_attest_key_fails_missing_challenge() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    // Create RSA attestation key.
+    let attestation_key_metadata = key_generations::generate_attestation_key(
+        &sec_level,
+        Algorithm::RSA,
+        att_challenge,
+        att_app_id,
+    )
+    .unwrap();
+
+    let mut cert_chain: Vec<u8> = Vec::new();
+    cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+    cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+    validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+
+    // Try to attest RSA signing key without providing attestation challenge.
+    let sign_key_alias = format!("ksrsa_attested_test_key_missing_challenge{}", getuid());
+    let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(sign_key_alias),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+            digest: Some(Digest::SHA_2_256),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: None,
+            att_app_id: Some(att_app_id.to_vec()),
+        },
+        Some(&attestation_key_metadata.key),
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::ATTESTATION_CHALLENGE_MISSING), result.unwrap_err());
+}
+
+/// Generate an asymmetric key which doesn't possess ATTEST_KEY purpose. Try to use this key as
+/// attestation key while generating RSA key. Test should fail to generate a key with error
+/// code `INCOMPATIBLE_PURPOSE`.
+#[test]
+fn keystore2_attest_rsa_key_with_non_attest_key_fails_incompat_purpose_error() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    let alias = format!("non_attest_key_{}", getuid());
+    let non_attest_key_metadata = key_generations::generate_ec_p256_signing_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias),
+        None,
+        None,
+    )
+    .unwrap();
+
+    // Try to generate RSA signing key with non-attestation key to sign it.
+    let sign_key_alias = format!("ksrsa_attested_sign_test_key_non_attest_{}", getuid());
+    let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(sign_key_alias),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+            digest: Some(Digest::SHA_2_256),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: Some(att_challenge.to_vec()),
+            att_app_id: Some(att_app_id.to_vec()),
+        },
+        Some(&non_attest_key_metadata.key),
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Generate a symmetric key. Try to use this symmetric key as attestation key while generating RSA
+/// key. Test should fail to generate a key with response code `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_attest_rsa_key_with_symmetric_key_fails_sys_error() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    let alias = "aes_attest_key";
+    let sym_key_metadata = key_generations::generate_sym_key(
+        &sec_level,
+        Algorithm::AES,
+        128,
+        alias,
+        &PaddingMode::NONE,
+        &BlockMode::ECB,
+        None,
+    )
+    .unwrap();
+
+    // Try to generate RSA signing key with symmetric key as attestation key.
+    let sign_key_alias = format!("ksrsa_attested_sign_test_key_sym_attest_{}", getuid());
+    let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(sign_key_alias),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+            digest: Some(Digest::SHA_2_256),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: Some(att_challenge.to_vec()),
+            att_app_id: Some(att_app_id.to_vec()),
+        },
+        Some(&sym_key_metadata.key),
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Generate RSA attestation key and try to use it as attestation key while generating symmetric
+/// key. Test should generate symmetric key successfully. Verify that generated symmetric key
+/// should not have attestation record or certificate.
+#[test]
+fn keystore2_attest_symmetric_key_fail_sys_error() {
+    skip_test_if_no_app_attest_key_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    let att_challenge: &[u8] = b"foo";
+    let att_app_id: &[u8] = b"bar";
+
+    // Create attestation key.
+    let attestation_key_metadata = key_generations::generate_attestation_key(
+        &sec_level,
+        Algorithm::RSA,
+        att_challenge,
+        att_app_id,
+    )
+    .unwrap();
+
+    let mut cert_chain: Vec<u8> = Vec::new();
+    cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
+    cert_chain.extend(attestation_key_metadata.certificateChain.as_ref().unwrap());
+    validate_certchain(&cert_chain).expect("Error while validating cert chain.");
+
+    // Generate symmetric key with above generated key as attestation key.
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::AES)
+        .purpose(KeyPurpose::ENCRYPT)
+        .purpose(KeyPurpose::DECRYPT)
+        .key_size(128)
+        .padding_mode(PaddingMode::NONE)
+        .block_mode(BlockMode::ECB)
+        .attestation_challenge(att_challenge.to_vec())
+        .attestation_app_id(att_app_id.to_vec());
+
+    let alias = format!("ks_test_sym_key_attest_{}", getuid());
+    let aes_key_metadata = sec_level
+        .generateKey(
+            &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+            Some(&attestation_key_metadata.key),
+            &gen_params,
+            0,
+            b"entropy",
+        )
+        .unwrap();
+
+    // Should not have public certificate.
+    assert!(aes_key_metadata.certificate.is_none());
+
+    // Should not have an attestation record.
+    assert!(aes_key_metadata.certificateChain.is_none());
+}
diff --git a/keystore2/tests/keystore2_client_ec_key_tests.rs b/keystore2/tests/keystore2_client_ec_key_tests.rs
index 60bcddf..726d61c 100644
--- a/keystore2/tests/keystore2_client_ec_key_tests.rs
+++ b/keystore2/tests/keystore2_client_ec_key_tests.rs
@@ -20,7 +20,9 @@
     KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+    CreateOperationResponse::CreateOperationResponse, Domain::Domain,
+    IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+    ResponseCode::ResponseCode,
 };
 
 use keystore2_test_utils::{
@@ -28,9 +30,171 @@
 };
 
 use crate::keystore2_client_test_utils::{
-    execute_op_run_as_child, perform_sample_sign_operation, BarrierReached, ForcedOp, TestOutcome,
+    delete_app_key, execute_op_run_as_child, perform_sample_sign_operation, BarrierReached,
+    ForcedOp, TestOutcome,
 };
 
+macro_rules! test_ec_sign_key_op_success {
+    ( $test_name:ident, $digest:expr, $ec_curve:expr ) => {
+        #[test]
+        fn $test_name() {
+            perform_ec_sign_key_op_success(stringify!($test_name), $digest, $ec_curve);
+        }
+    };
+}
+
+macro_rules! test_ec_sign_key_op_with_none_or_md5_digest {
+    ( $test_name:ident, $digest:expr, $ec_curve:expr ) => {
+        #[test]
+        fn $test_name() {
+            perform_ec_sign_key_op_with_none_or_md5_digest(
+                stringify!($test_name),
+                $digest,
+                $ec_curve,
+            );
+        }
+    };
+}
+
+fn create_ec_key_and_operation(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+    digest: Digest,
+    ec_curve: EcCurve,
+) -> binder::Result<CreateOperationResponse> {
+    let key_metadata =
+        key_generations::generate_ec_key(sec_level, domain, nspace, alias, ec_curve, digest)?;
+
+    sec_level.createOperation(
+        &key_metadata.key,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
+        false,
+    )
+}
+
+fn perform_ec_sign_key_op_success(alias: &str, digest: Digest, ec_curve: EcCurve) {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let op_response = create_ec_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        digest,
+        ec_curve,
+    )
+    .unwrap();
+
+    assert!(op_response.iOperation.is_some());
+    assert_eq!(
+        Ok(()),
+        key_generations::map_ks_error(perform_sample_sign_operation(
+            &op_response.iOperation.unwrap()
+        ))
+    );
+
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+fn perform_ec_sign_key_op_with_none_or_md5_digest(alias: &str, digest: Digest, ec_curve: EcCurve) {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    match key_generations::map_ks_error(create_ec_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        digest,
+        ec_curve,
+    )) {
+        Ok(op_response) => {
+            assert!(op_response.iOperation.is_some());
+            assert_eq!(
+                Ok(()),
+                key_generations::map_ks_error(perform_sample_sign_operation(
+                    &op_response.iOperation.unwrap()
+                ))
+            );
+        }
+        Err(e) => {
+            assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_DIGEST));
+            assert!(digest == Digest::NONE || digest == Digest::MD5);
+        }
+    }
+
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+// Below macros generate tests for generating EC keys with curves EcCurve::P_224, EcCurve::P_256,
+// EcCurve::P_384, EcCurve::P_521 and various digest modes. Tests tries to create operations using
+// the generated keys. Operations with digest modes `SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and
+// SHA-2 512` should be created  successfully. Creation of operations with digest modes NONE and
+// MD5 should fail with an error code `UNSUPPORTED_DIGEST`.
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_none_ec_p224,
+    Digest::NONE,
+    EcCurve::P_224
+);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_md5_ec_p224,
+    Digest::MD5,
+    EcCurve::P_224
+);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p224, Digest::SHA1, EcCurve::P_224);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p224, Digest::SHA_2_224, EcCurve::P_224);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p224, Digest::SHA_2_256, EcCurve::P_224);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p224, Digest::SHA_2_384, EcCurve::P_224);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p224, Digest::SHA_2_512, EcCurve::P_224);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_none_ec_p256,
+    Digest::NONE,
+    EcCurve::P_256
+);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_md5_ec_p256,
+    Digest::MD5,
+    EcCurve::P_256
+);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p256, Digest::SHA1, EcCurve::P_256);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p256, Digest::SHA_2_224, EcCurve::P_256);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p256, Digest::SHA_2_256, EcCurve::P_256);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p256, Digest::SHA_2_384, EcCurve::P_256);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p256, Digest::SHA_2_512, EcCurve::P_256);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_none_ec_p384,
+    Digest::NONE,
+    EcCurve::P_384
+);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_md5_ec_p384,
+    Digest::MD5,
+    EcCurve::P_384
+);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p384, Digest::SHA1, EcCurve::P_384);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p384, Digest::SHA_2_224, EcCurve::P_384);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p384, Digest::SHA_2_256, EcCurve::P_384);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p384, Digest::SHA_2_384, EcCurve::P_384);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p384, Digest::SHA_2_512, EcCurve::P_384);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_none_ec_p521,
+    Digest::NONE,
+    EcCurve::P_521
+);
+test_ec_sign_key_op_with_none_or_md5_digest!(
+    sign_ec_key_op_md5_ec_p521,
+    Digest::MD5,
+    EcCurve::P_521
+);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p521, Digest::SHA1, EcCurve::P_521);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p521, Digest::SHA_2_224, EcCurve::P_521);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p521, Digest::SHA_2_256, EcCurve::P_521);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p521, Digest::SHA_2_384, EcCurve::P_521);
+test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p521, Digest::SHA_2_512, EcCurve::P_521);
+
 /// This test will try to load the key with Domain::BLOB.
 /// INVALID_ARGUMENT error is expected.
 #[test]
@@ -66,7 +230,7 @@
     let alias = format!("ks_invalid_test_key_{}", getuid());
 
     let result = key_generations::map_ks_error(key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain(99), // Invalid domain.
         key_generations::SELINUX_SHELL_NAMESPACE,
         Some(alias),
@@ -146,64 +310,6 @@
     assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
 }
 
-/// Generate EC keys with curves EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521 and
-/// various digest modes. Try to create operations using generated keys. Operations with digest
-/// modes `SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512` should be created  successfully.
-/// Creation of operations with digest modes NONE and MD5 should fail with an error code
-/// `UNSUPPORTED_DIGEST`.
-#[test]
-fn keystore2_ec_generate_key() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let digests = [
-        Digest::NONE,
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
-
-    let ec_curves = [EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521];
-
-    for ec_curve in ec_curves {
-        for digest in digests {
-            let alias = format!("ks_ec_test_key_gen_{}{}{}", getuid(), ec_curve.0, digest.0);
-            let key_metadata = key_generations::generate_ec_key(
-                &*sec_level,
-                Domain::APP,
-                -1,
-                Some(alias.to_string()),
-                ec_curve,
-                digest,
-            )
-            .unwrap();
-
-            match key_generations::map_ks_error(sec_level.createOperation(
-                &key_metadata.key,
-                &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
-                false,
-            )) {
-                Ok(op_response) => {
-                    assert!(op_response.iOperation.is_some());
-                    assert_eq!(
-                        Ok(()),
-                        key_generations::map_ks_error(perform_sample_sign_operation(
-                            &op_response.iOperation.unwrap()
-                        ))
-                    );
-                }
-                Err(e) => {
-                    assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_DIGEST));
-                    assert!(digest == Digest::NONE || digest == Digest::MD5);
-                }
-            }
-        }
-    }
-}
-
 /// Generate EC key with curve `CURVE_25519` and digest mode NONE. Try to create an operation using
 /// generated key. `CURVE_25519` key should support `Digest::NONE` digest mode and test should be
 /// able to create an operation successfully.
@@ -214,7 +320,7 @@
 
     let alias = format!("ks_ec_25519_none_test_key_gen_{}", getuid());
     let key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias),
@@ -260,7 +366,7 @@
     for digest in digests {
         let alias = format!("ks_ec_25519_test_key_gen_{}{}", getuid(), digest.0);
         let key_metadata = key_generations::generate_ec_key(
-            &*sec_level,
+            &sec_level,
             Domain::APP,
             -1,
             Some(alias.to_string()),
@@ -289,7 +395,7 @@
 
     let alias = "ks_ec_test_incomp_key_digest";
     let key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias.to_string()),
@@ -378,7 +484,7 @@
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
     let key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::BLOB,
         key_generations::SELINUX_SHELL_NAMESPACE,
         None,
diff --git a/keystore2/tests/keystore2_client_import_keys_tests.rs b/keystore2/tests/keystore2_client_import_keys_tests.rs
new file mode 100644
index 0000000..abf35b5
--- /dev/null
+++ b/keystore2/tests/keystore2_client_import_keys_tests.rs
@@ -0,0 +1,374 @@
+// 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.
+
+use nix::unistd::getuid;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+    ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+    SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+};
+
+use keystore2_test_utils::{
+    authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use crate::keystore2_client_test_utils::{
+    has_trusty_keymint, perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
+    perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
+};
+
+pub fn import_rsa_sign_key_and_perform_sample_operation(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    domain: Domain,
+    nspace: i64,
+    alias: Option<String>,
+    import_params: authorizations::AuthSetBuilder,
+) {
+    let key_metadata =
+        key_generations::import_rsa_2048_key(sec_level, domain, nspace, alias, import_params)
+            .unwrap();
+
+    perform_sample_asym_sign_verify_op(
+        sec_level,
+        &key_metadata,
+        Some(PaddingMode::RSA_PSS),
+        Some(Digest::SHA_2_256),
+    );
+}
+
+/// Import RSA key and verify imported key parameters. Try to create an operation using the
+/// imported key. Test should be able to create an operation successfully.
+#[test]
+fn keystore2_rsa_import_key_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_rsa_key_test_import_1_{}{}", getuid(), 2048);
+
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .digest(Digest::SHA_2_256)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .padding_mode(PaddingMode::RSA_PSS)
+        .key_size(2048)
+        .rsa_public_exponent(65537)
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    import_rsa_sign_key_and_perform_sample_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias),
+        import_params,
+    );
+}
+
+/// Import RSA key without providing key-size and public exponent in import key parameters list.
+/// Let Key-size and public-exponent to be determined from the imported key material. Verify
+/// imported key parameters. Try to create an operation using the imported key. Test should be
+/// able to create an operation successfully.
+#[test]
+fn keystore2_rsa_import_key_determine_key_size_and_pub_exponent() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_rsa_key_test_import_2_{}{}", getuid(), 2048);
+
+    // key-size and public-exponent shouldn't be specified in import key parameters list.
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .digest(Digest::SHA_2_256)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .padding_mode(PaddingMode::RSA_PSS)
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    import_rsa_sign_key_and_perform_sample_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias),
+        import_params,
+    );
+}
+
+/// Try to import RSA key with wrong key size as import-key-parameter. Test should fail to import
+/// a key with `IMPORT_PARAMETER_MISMATCH` error code.
+#[test]
+fn keystore2_rsa_import_key_fails_with_keysize_param_mismatch_error() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_rsa_key_test_import_3_{}{}", getuid(), 2048);
+
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .digest(Digest::SHA_2_256)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .padding_mode(PaddingMode::RSA_PSS)
+        .key_size(1024) // Wrong key size is specified, (actual key-size is 2048).
+        .rsa_public_exponent(65537)
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    let result = key_generations::map_ks_error(sec_level.importKey(
+        &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+        None,
+        &import_params,
+        0,
+        key_generations::RSA_2048_KEY,
+    ));
+
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::IMPORT_PARAMETER_MISMATCH), result.unwrap_err());
+}
+
+/// Try to import RSA key with wrong public-exponent as import-key-parameter.
+/// Test should fail to import a key with `IMPORT_PARAMETER_MISMATCH` error code.
+#[test]
+fn keystore2_rsa_import_key_fails_with_public_exponent_param_mismatch_error() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_rsa_key_test_import_4_{}{}", getuid(), 2048);
+
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .digest(Digest::SHA_2_256)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .padding_mode(PaddingMode::RSA_PSS)
+        .key_size(2048)
+        .rsa_public_exponent(3) // This doesn't match the key.
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    let result = key_generations::map_ks_error(sec_level.importKey(
+        &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+        None,
+        &import_params,
+        0,
+        key_generations::RSA_2048_KEY,
+    ));
+
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::IMPORT_PARAMETER_MISMATCH), result.unwrap_err());
+}
+
+/// Try to import a key with multiple purposes. Test should fail to import a key with
+/// `INCOMPATIBLE_PURPOSE` error code. If the backend is `keymaster` then `importKey` shall be
+/// successful.
+#[test]
+fn keystore2_rsa_import_key_with_multipurpose_fails_incompt_purpose_error() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_rsa_key_test_import_5_{}{}", getuid(), 2048);
+
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .digest(Digest::SHA_2_256)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::ATTEST_KEY)
+        .padding_mode(PaddingMode::RSA_PSS)
+        .key_size(2048)
+        .rsa_public_exponent(65537)
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    let result = key_generations::map_ks_error(sec_level.importKey(
+        &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+        None,
+        &import_params,
+        0,
+        key_generations::RSA_2048_KEY,
+    ));
+
+    if has_trusty_keymint() {
+        assert!(result.is_err());
+        assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+    } else {
+        assert!(result.is_ok());
+    }
+}
+
+/// Import EC key and verify imported key parameters. Let ec-curve to be determined from the
+/// imported key material. Try to create an operation using the imported key. Test should be
+/// able to create an operation successfully.
+#[test]
+fn keystore2_import_ec_key_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_ec_key_test_import_1_{}{}", getuid(), 256);
+
+    // Don't specify ec-curve.
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .digest(Digest::SHA_2_256)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    let key_metadata = key_generations::import_ec_p_256_key(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias),
+        import_params,
+    )
+    .expect("Failed to import EC key.");
+
+    perform_sample_asym_sign_verify_op(&sec_level, &key_metadata, None, Some(Digest::SHA_2_256));
+}
+
+/// Try to import EC key with wrong ec-curve as import-key-parameter. Test should fail to import a
+/// key with `IMPORT_PARAMETER_MISMATCH` error code.
+#[test]
+fn keystore2_ec_import_key_fails_with_mismatch_curve_error() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_ec_key_test_import_1_{}{}", getuid(), 256);
+
+    let import_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_224) // It doesn't match with key material.
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .cert_not_before(0)
+        .cert_not_after(253402300799000);
+
+    let result = key_generations::map_ks_error(sec_level.importKey(
+        &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+        None,
+        &import_params,
+        0,
+        key_generations::EC_P_256_KEY,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::IMPORT_PARAMETER_MISMATCH), result.unwrap_err());
+}
+
+/// Import AES key and verify key parameters. Try to create an operation using the imported key.
+/// Test should be able to create an operation successfully.
+#[test]
+fn keystore2_import_aes_key_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_aes_key_test_import_1_{}{}", getuid(), 256);
+    let key_metadata = key_generations::import_aes_key(&sec_level, Domain::APP, -1, Some(alias))
+        .expect("Failed to import AES key.");
+
+    let cipher_text = perform_sample_sym_key_encrypt_op(
+        &sec_level,
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+
+    assert!(cipher_text.is_some());
+
+    let plain_text = perform_sample_sym_key_decrypt_op(
+        &sec_level,
+        &cipher_text.unwrap(),
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+
+    assert!(plain_text.is_some());
+    assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+}
+
+/// Import 3DES key and verify key parameters. Try to create an operation using the imported key.
+/// Test should be able to create an operation successfully.
+#[test]
+fn keystore2_import_3des_key_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = key_generations::map_ks_error(
+        keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT),
+    )
+    .unwrap();
+
+    let alias = format!("ks_3des_key_test_import_1_{}{}", getuid(), 168);
+
+    let key_metadata = key_generations::import_3des_key(&sec_level, Domain::APP, -1, Some(alias))
+        .expect("Failed to import 3DES key.");
+
+    let cipher_text = perform_sample_sym_key_encrypt_op(
+        &sec_level,
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+
+    assert!(cipher_text.is_some());
+
+    let plain_text = perform_sample_sym_key_decrypt_op(
+        &sec_level,
+        &cipher_text.unwrap(),
+        PaddingMode::PKCS7,
+        BlockMode::ECB,
+        &mut None,
+        None,
+        &key_metadata.key,
+    )
+    .unwrap();
+
+    assert!(plain_text.is_some());
+    assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+}
+
+/// Import HMAC key and verify key parameters. Try to create an operation using the imported key.
+/// Test should be able to create an operation successfully.
+#[test]
+fn keystore2_import_hmac_key_success() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = format!("ks_hmac_key_test_import_1_{}", getuid());
+
+    let key_metadata = key_generations::import_hmac_key(&sec_level, Domain::APP, -1, Some(alias))
+        .expect("Failed to import HMAC key.");
+
+    perform_sample_hmac_sign_verify_op(&sec_level, &key_metadata.key);
+}
diff --git a/keystore2/tests/keystore2_client_key_id_domain_tests.rs b/keystore2/tests/keystore2_client_key_id_domain_tests.rs
index 2a1d990..09b1378 100644
--- a/keystore2/tests/keystore2_client_key_id_domain_tests.rs
+++ b/keystore2/tests/keystore2_client_key_id_domain_tests.rs
@@ -37,7 +37,7 @@
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
     let result = key_generations::map_ks_error(key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::KEY_ID,
         key_generations::SELINUX_SHELL_NAMESPACE,
         Some(alias.to_string()),
@@ -58,7 +58,7 @@
     let alias = "ks_key_id_test_key";
 
     let key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias.to_string()),
@@ -115,7 +115,7 @@
     let alias = format!("ks_key_id_test_alias_rebind_1_{}", getuid());
 
     let key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias.to_string()),
@@ -127,7 +127,7 @@
     // Generate a key with same alias as above generated key, so that alias will be rebound
     // to this key.
     let new_key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias),
@@ -182,7 +182,7 @@
     let alias = format!("ks_key_id_test_alias_rebind_2_{}", getuid());
 
     let key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias.to_string()),
@@ -210,7 +210,7 @@
     // Generate another key with same alias as above generated key, so that alias will be rebound
     // to this key.
     let new_key_metadata = key_generations::generate_ec_key(
-        &*sec_level,
+        &sec_level,
         Domain::APP,
         -1,
         Some(alias),
diff --git a/keystore2/tests/keystore2_client_rsa_key_tests.rs b/keystore2/tests/keystore2_client_rsa_key_tests.rs
index aa822b9..3139c2b 100644
--- a/keystore2/tests/keystore2_client_rsa_key_tests.rs
+++ b/keystore2/tests/keystore2_client_rsa_key_tests.rs
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use nix::unistd::getuid;
-
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     BlockMode::BlockMode, Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
     PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
@@ -27,7 +25,59 @@
     authorizations, get_keystore_service, key_generations, key_generations::Error,
 };
 
-use crate::keystore2_client_test_utils::{perform_sample_sign_operation, ForcedOp};
+use crate::keystore2_client_test_utils::{
+    delete_app_key, has_trusty_keymint, perform_sample_sign_operation, ForcedOp,
+};
+
+/// This macro is used for creating signing key operation tests using digests and paddings
+/// for various key sizes.
+macro_rules! test_rsa_sign_key_op {
+    ( $test_name:ident, $digest:expr, $key_size:expr, $padding:expr ) => {
+        #[test]
+        fn $test_name() {
+            perform_rsa_sign_key_op_success($digest, $key_size, stringify!($test_name), $padding);
+        }
+    };
+
+    ( $test_name:ident, $digest:expr, $padding:expr ) => {
+        #[test]
+        fn $test_name() {
+            perform_rsa_sign_key_op_failure($digest, stringify!($test_name), $padding);
+        }
+    };
+}
+
+/// This macro is used for creating encrypt/decrypt key operation tests using digests, mgf-digests
+/// and paddings for various key sizes.
+macro_rules! test_rsa_encrypt_key_op {
+    ( $test_name:ident, $digest:expr, $key_size:expr, $padding:expr ) => {
+        #[test]
+        fn $test_name() {
+            create_rsa_encrypt_decrypt_key_op_success(
+                $digest,
+                $key_size,
+                stringify!($test_name),
+                $padding,
+                None,
+                None,
+            );
+        }
+    };
+
+    ( $test_name:ident, $digest:expr, $key_size:expr, $padding:expr, $mgf_digest:expr ) => {
+        #[test]
+        fn $test_name() {
+            create_rsa_encrypt_decrypt_key_op_success(
+                $digest,
+                $key_size,
+                stringify!($test_name),
+                $padding,
+                $mgf_digest,
+                Some(BlockMode::ECB),
+            );
+        }
+    };
+}
 
 /// Generate a RSA key and create an operation using the generated key.
 fn create_rsa_key_and_operation(
@@ -60,115 +110,1431 @@
     sec_level.createOperation(&key_metadata.key, &op_params, forced_op.0)
 }
 
-/// Generate RSA signing keys with -
-///     Padding mode: RSA_PKCS1_1_5_SIGN
-///     Digest modes: `NONE, MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create operations with these generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_pkcs1_1_5() {
+/// Generate RSA signing key with given parameters and perform signing operation.
+fn perform_rsa_sign_key_op_success(
+    digest: Digest,
+    key_size: i32,
+    alias: &str,
+    padding: PaddingMode,
+) {
     let keystore2 = get_keystore_service();
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
-    let digests = [
-        Digest::NONE,
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
+    let op_response = create_rsa_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        &key_generations::KeyParams {
+            key_size,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(padding),
+            digest: Some(digest),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: None,
+            att_app_id: None,
+        },
+        KeyPurpose::SIGN,
+        ForcedOp(false),
+    )
+    .expect("Failed to create an operation.");
 
-    let key_sizes = [2048, 3072, 4096];
+    assert!(op_response.iOperation.is_some());
+    assert_eq!(
+        Ok(()),
+        key_generations::map_ks_error(perform_sample_sign_operation(
+            &op_response.iOperation.unwrap()
+        ))
+    );
 
-    for key_size in key_sizes {
-        for digest in digests {
-            let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
-            let op_response = create_rsa_key_and_operation(
-                &sec_level,
-                Domain::APP,
-                -1,
-                Some(alias.to_string()),
-                &key_generations::KeyParams {
-                    key_size,
-                    purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
-                    padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
-                    digest: Some(digest),
-                    mgf_digest: None,
-                    block_mode: None,
-                    att_challenge: None,
-                    att_app_id: None,
-                },
-                KeyPurpose::SIGN,
-                ForcedOp(false),
-            )
-            .unwrap();
-
-            assert!(op_response.iOperation.is_some());
-            assert_eq!(
-                Ok(()),
-                key_generations::map_ks_error(perform_sample_sign_operation(
-                    &op_response.iOperation.unwrap()
-                ))
-            );
-        } // End of digests.
-    } // End of key-sizes.
+    delete_app_key(&keystore2, alias).unwrap();
 }
 
-/// Generate RSA signing keys with -
-///     Padding mode: RSA_PSS
-///     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create operations with these generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_pss_success() {
+/// Generate RSA signing key with given parameters and try to perform signing operation.
+/// Error `INCOMPATIBLE_DIGEST | UNKNOWN_ERROR` is expected while creating an opearation.
+fn perform_rsa_sign_key_op_failure(digest: Digest, alias: &str, padding: PaddingMode) {
     let keystore2 = get_keystore_service();
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
-    let digests = [
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
+    let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(padding),
+            digest: Some(digest),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: None,
+            att_app_id: None,
+        },
+        KeyPurpose::SIGN,
+        ForcedOp(false),
+    ));
+    assert!(result.is_err());
 
-    let key_sizes = [2048, 3072, 4096];
+    if has_trusty_keymint() {
+        assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::UNKNOWN_ERROR));
+    } else {
+        assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::INCOMPATIBLE_DIGEST));
+    }
 
-    for key_size in key_sizes {
-        for digest in digests {
-            let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
-            let op_response = create_rsa_key_and_operation(
-                &sec_level,
-                Domain::APP,
-                -1,
-                Some(alias.to_string()),
-                &key_generations::KeyParams {
-                    key_size,
-                    purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
-                    padding: Some(PaddingMode::RSA_PSS),
-                    digest: Some(digest),
-                    mgf_digest: None,
-                    block_mode: None,
-                    att_challenge: None,
-                    att_app_id: None,
-                },
-                KeyPurpose::SIGN,
-                ForcedOp(false),
-            )
-            .unwrap();
-
-            assert!(op_response.iOperation.is_some());
-            assert_eq!(
-                Ok(()),
-                key_generations::map_ks_error(perform_sample_sign_operation(
-                    &op_response.iOperation.unwrap()
-                ))
-            );
-        } // End of digests.
-    } // End of key-sizes.
+    delete_app_key(&keystore2, alias).unwrap();
 }
 
+/// Generate RSA encrypt/decrypt key with given parameters and perform decrypt operation.
+fn create_rsa_encrypt_decrypt_key_op_success(
+    digest: Option<Digest>,
+    key_size: i32,
+    alias: &str,
+    padding: PaddingMode,
+    mgf_digest: Option<Digest>,
+    block_mode: Option<BlockMode>,
+) {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let result = create_rsa_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        &key_generations::KeyParams {
+            key_size,
+            purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+            padding: Some(padding),
+            digest,
+            mgf_digest,
+            block_mode,
+            att_challenge: None,
+            att_app_id: None,
+        },
+        KeyPurpose::DECRYPT,
+        ForcedOp(false),
+    );
+
+    assert!(result.is_ok());
+
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+// Below macros generate tests for generating RSA signing keys with -
+//     Padding mode: RSA_PKCS1_1_5_SIGN
+//     Digest modes: `NONE, MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+// and create operations with generated keys. Tests should create operations successfully.
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_none_2048,
+    Digest::NONE,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_md5_2048,
+    Digest::MD5,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha1_2048,
+    Digest::SHA1,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha224_2048,
+    Digest::SHA_2_224,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha256_2048,
+    Digest::SHA_2_256,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha384_2048,
+    Digest::SHA_2_384,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha512_2048,
+    Digest::SHA_2_512,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_none_3072,
+    Digest::NONE,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_md5_3072,
+    Digest::MD5,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha1_3072,
+    Digest::SHA1,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha224_3072,
+    Digest::SHA_2_224,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha256_3072,
+    Digest::SHA_2_256,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha384_3072,
+    Digest::SHA_2_384,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha512_3072,
+    Digest::SHA_2_512,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_none_4096,
+    Digest::NONE,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_md5_4096,
+    Digest::MD5,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha1_4096,
+    Digest::SHA1,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha224_4096,
+    Digest::SHA_2_224,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha256_4096,
+    Digest::SHA_2_256,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha384_4096,
+    Digest::SHA_2_384,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+test_rsa_sign_key_op!(
+    sign_key_pkcs1_1_5_sha512_4096,
+    Digest::SHA_2_512,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_SIGN
+);
+
+// Below macros generate tests for generating RSA signing keys with -
+//     Padding mode: RSA_PSS
+//     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+// and create operations with generated keys. Tests should create operations
+// successfully.
+test_rsa_sign_key_op!(sign_key_pss_md5_2048, Digest::MD5, 2048, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha1_2048, Digest::SHA1, 2048, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha224_2048, Digest::SHA_2_224, 2048, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha256_2048, Digest::SHA_2_256, 2048, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha384_2048, Digest::SHA_2_384, 2048, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha512_2048, Digest::SHA_2_512, 2048, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_md5_3072, Digest::MD5, 3072, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha1_3072, Digest::SHA1, 3072, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha224_3072, Digest::SHA_2_224, 3072, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha256_3072, Digest::SHA_2_256, 3072, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha384_3072, Digest::SHA_2_384, 3072, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha512_3072, Digest::SHA_2_512, 3072, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_md5_4096, Digest::MD5, 4096, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha1_4096, Digest::SHA1, 4096, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha224_4096, Digest::SHA_2_224, 4096, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha256_4096, Digest::SHA_2_256, 4096, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha384_4096, Digest::SHA_2_384, 4096, PaddingMode::RSA_PSS);
+test_rsa_sign_key_op!(sign_key_pss_sha512_4096, Digest::SHA_2_512, 4096, PaddingMode::RSA_PSS);
+
+// Below macros generate tests for generating RSA signing keys with -
+//     Padding mode: `NONE`
+//     Digest mode `NONE`
+// and try to create operations with generated keys. Tests should create operations
+// successfully.
+test_rsa_sign_key_op!(sign_key_none_none_2048, Digest::NONE, 2048, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_none_3072, Digest::NONE, 3072, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_none_4096, Digest::NONE, 4096, PaddingMode::NONE);
+
+// Below macros generate tests for generating RSA signing keys with -
+//     Padding mode: `NONE`
+//     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+// and create operations with generated keys. Tests should fail to create operations with
+// an error code `UNKNOWN_ERROR | INCOMPATIBLE_DIGEST`.
+test_rsa_sign_key_op!(sign_key_none_md5_2048, Digest::MD5, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_sha1_2048, Digest::SHA1, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_sha224_2048, Digest::SHA_2_224, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_sha256_2048, Digest::SHA_2_256, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_sha384_2048, Digest::SHA_2_384, PaddingMode::NONE);
+test_rsa_sign_key_op!(sign_key_none_sha512_2048, Digest::SHA_2_512, PaddingMode::NONE);
+
+// Below macros generate tests for generating RSA encryption keys with various digest mode
+// and padding mode combinations.
+//     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+//     Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
+// and try to create operations using generated keys, tests should create operations successfully.
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_none_2048,
+    Some(Digest::NONE),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_md5_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha1_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha224_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha256_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha384_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha512_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_none_3072,
+    Some(Digest::NONE),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_md5_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha1_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha224_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha256_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha384_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha512_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_none_4096,
+    Some(Digest::NONE),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_md5_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha1_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha224_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha256_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha384_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_sha512_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT
+);
+test_rsa_encrypt_key_op!(encrypt_key_none_none_2048, Some(Digest::NONE), 2048, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(encrypt_key_none_md5_2048, Some(Digest::MD5), 2048, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(encrypt_key_none_sha1_2048, Some(Digest::SHA1), 2048, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha224_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha256_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha384_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha512_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(encrypt_key_none_none_3072, Some(Digest::NONE), 3072, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(encrypt_key_none_md5_3072, Some(Digest::MD5), 3072, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(encrypt_key_none_sha1_3072, Some(Digest::SHA1), 3072, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha224_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha256_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha384_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha512_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(encrypt_key_none_none_4096, Some(Digest::NONE), 4096, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(encrypt_key_none_md5_4096, Some(Digest::MD5), 4096, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(encrypt_key_none_sha1_4096, Some(Digest::SHA1), 4096, PaddingMode::NONE);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha224_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha256_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha384_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::NONE
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_none_sha512_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::NONE
+);
+
+// Below macros generate tests for generating RSA keys with -
+//     Padding Mode: `RSA_OAEP`
+//     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+//     mgf-digests: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+// and create a decrypt operations using generated keys. Tests should create operations
+// successfully.
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_md5_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha1_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha224_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha256_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha384_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha512_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_md5_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha1_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha224_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha256_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha384_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha512_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_md5_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha1_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha224_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha256_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha384_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha512_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_md5_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha1_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha224_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha256_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha384_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha512_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_md5_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha1_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha224_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha256_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha384_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha512_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_md5_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha1_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha224_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha256_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha384_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha512_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_md5_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha1_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha224_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha256_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha384_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha512_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_md5_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha1_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha224_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha256_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha384_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha512_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_md5_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha1_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha224_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha256_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha384_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha512_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_md5_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha1_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha224_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha256_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha384_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha512_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_md5_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha1_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha224_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha256_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha384_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha512_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_md5_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha1_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha224_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha256_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha384_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha512_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_md5_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha1_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha224_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha256_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha384_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_sha512_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_md5_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha1_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha224_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha256_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha384_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_sha512_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_md5_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha1_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha224_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha256_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha384_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_sha512_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_md5_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha1_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha224_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha256_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha384_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_sha512_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_md5_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha1_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha224_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha256_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha384_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_sha512_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_md5_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::MD5)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha1_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA1)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha224_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_224)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha256_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_256)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha384_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_384)
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_sha512_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    Some(Digest::SHA_2_512)
+);
+
+// Below macros generate tests for generating RSA keys with -
+//     Padding mode: `RSA_OAEP`
+//     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+// and create a decrypt operations using generated keys. Tests should create operations
+// successfully.
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_no_mgf_2048,
+    Some(Digest::MD5),
+    2048,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_no_mgf_2048,
+    Some(Digest::SHA1),
+    2048,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_no_mgf_2048,
+    Some(Digest::SHA_2_224),
+    2048,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_no_mgf_2048,
+    Some(Digest::SHA_2_256),
+    2048,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_no_mgf_2048,
+    Some(Digest::SHA_2_384),
+    2048,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_no_mgf_2048,
+    Some(Digest::SHA_2_512),
+    2048,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_no_mgf_3072,
+    Some(Digest::MD5),
+    3072,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_no_mgf_3072,
+    Some(Digest::SHA1),
+    3072,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_no_mgf_3072,
+    Some(Digest::SHA_2_224),
+    3072,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_no_mgf_3072,
+    Some(Digest::SHA_2_256),
+    3072,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_no_mgf_3072,
+    Some(Digest::SHA_2_384),
+    3072,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_no_mgf_3072,
+    Some(Digest::SHA_2_512),
+    3072,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_md5_no_mgf_4096,
+    Some(Digest::MD5),
+    4096,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha1_no_mgf_4096,
+    Some(Digest::SHA1),
+    4096,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha224_no_mgf_4096,
+    Some(Digest::SHA_2_224),
+    4096,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha256_no_mgf_4096,
+    Some(Digest::SHA_2_256),
+    4096,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha384_no_mgf_4096,
+    Some(Digest::SHA_2_384),
+    4096,
+    PaddingMode::RSA_OAEP,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_oaep_sha512_no_mgf_4096,
+    Some(Digest::SHA_2_512),
+    4096,
+    PaddingMode::RSA_OAEP,
+    None
+);
+
+// Below macros generate tests for generating RSA encryption keys with only padding modes.
+//     Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
+// and try to create operations using generated keys, tests should create operations
+// successfully.
+test_rsa_encrypt_key_op!(encrypt_key_none_pad_2048, None, 2048, PaddingMode::NONE, None);
+test_rsa_encrypt_key_op!(encrypt_key_none_pad_3072, None, 3072, PaddingMode::NONE, None);
+test_rsa_encrypt_key_op!(encrypt_key_none_pad_4096, None, 4096, PaddingMode::NONE, None);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_pad_2048,
+    None,
+    2048,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_pad_3072,
+    None,
+    3072,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+    None
+);
+test_rsa_encrypt_key_op!(
+    encrypt_key_pkcs1_1_5_pad_4096,
+    None,
+    4096,
+    PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+    None
+);
+
 /// Generate RSA signing key with -
 ///     Padding mode: RSA_PSS
 ///     Digest mode: `NONE`.
@@ -179,227 +1545,27 @@
     let keystore2 = get_keystore_service();
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        let alias = format!("ks_rsa_pss_none_key_test_{}{}", getuid(), key_size);
-        let result = key_generations::map_ks_error(create_rsa_key_and_operation(
-            &sec_level,
-            Domain::APP,
-            -1,
-            Some(alias.to_string()),
-            &key_generations::KeyParams {
-                key_size,
-                purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
-                padding: Some(PaddingMode::RSA_PSS),
-                digest: Some(Digest::NONE),
-                mgf_digest: None,
-                block_mode: None,
-                att_challenge: None,
-                att_app_id: None,
-            },
-            KeyPurpose::SIGN,
-            ForcedOp(false),
-        ));
-        assert!(result.is_err());
-        assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
-    }
-}
-
-/// Generate RSA signing key with -
-///     Padding mode: `NONE`
-///     Digest mode `NONE`
-/// Try to create an operation with this generated key. Test should create an operation successfully.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_none_success() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        let alias = format!("ks_rsa_pad_none_key_test_{}{}", getuid(), key_size);
-        let op_response = create_rsa_key_and_operation(
-            &sec_level,
-            Domain::APP,
-            -1,
-            Some(alias.to_string()),
-            &key_generations::KeyParams {
-                key_size,
-                purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
-                padding: Some(PaddingMode::NONE),
-                digest: Some(Digest::NONE),
-                mgf_digest: None,
-                block_mode: None,
-                att_challenge: None,
-                att_app_id: None,
-            },
-            KeyPurpose::SIGN,
-            ForcedOp(false),
-        )
-        .unwrap();
-
-        assert!(op_response.iOperation.is_some());
-        assert_eq!(
-            Ok(()),
-            key_generations::map_ks_error(perform_sample_sign_operation(
-                &op_response.iOperation.unwrap()
-            ))
-        );
-    }
-}
-
-/// Generate RSA signing keys with -
-///     Padding mode: `NONE`
-///     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create operations with these generated keys. Test should fail to create operations with
-/// an error code `UNKNOWN_ERROR`.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_none_fail() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let digests = [
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
-
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        for digest in digests {
-            let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
-            let result = key_generations::map_ks_error(create_rsa_key_and_operation(
-                &sec_level,
-                Domain::APP,
-                -1,
-                Some(alias.to_string()),
-                &key_generations::KeyParams {
-                    key_size,
-                    purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
-                    padding: Some(PaddingMode::NONE),
-                    digest: Some(digest),
-                    mgf_digest: None,
-                    block_mode: None,
-                    att_challenge: None,
-                    att_app_id: None,
-                },
-                KeyPurpose::SIGN,
-                ForcedOp(false),
-            ));
-            assert!(result.is_err());
-            assert_eq!(Error::Km(ErrorCode::UNKNOWN_ERROR), result.unwrap_err());
-        }
-    }
-}
-
-/// Generate RSA keys with -
-///     Padding Mode: `RSA_OAEP`
-///     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-///     mgf-digests: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create a decrypt operations using generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_key_with_oaep_padding_success() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let digests = [
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
-
-    let mgf_digests = [
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
-
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        for digest in digests {
-            for mgf_digest in mgf_digests {
-                let alias =
-                    format!("ks_rsa_key_pair_oaep_test_{}{}{}", getuid(), key_size, digest.0);
-                let result = create_rsa_key_and_operation(
-                    &sec_level,
-                    Domain::APP,
-                    -1,
-                    Some(alias.to_string()),
-                    &key_generations::KeyParams {
-                        key_size,
-                        purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
-                        padding: Some(PaddingMode::RSA_OAEP),
-                        digest: Some(digest),
-                        mgf_digest: Some(mgf_digest),
-                        block_mode: Some(BlockMode::ECB),
-                        att_challenge: None,
-                        att_app_id: None,
-                    },
-                    KeyPurpose::DECRYPT,
-                    ForcedOp(false),
-                );
-                assert!(result.is_ok());
-            } // End of mgf-digests.
-        } // End of digests.
-    } // End of key-sizes.
-}
-
-/// Generate RSA keys with -
-///     Padding mode: `RSA_OAEP`
-///     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create a decrypt operations using generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_key_with_oaep_padding_and_digests_success() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let digests = [
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
-
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        for digest in digests {
-            let alias = format!("ks_rsa_key_pair_oaep_test_{}{}{}", getuid(), key_size, digest.0);
-            let result = create_rsa_key_and_operation(
-                &sec_level,
-                Domain::APP,
-                -1,
-                Some(alias.to_string()),
-                &key_generations::KeyParams {
-                    key_size,
-                    purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
-                    padding: Some(PaddingMode::RSA_OAEP),
-                    digest: Some(digest),
-                    mgf_digest: None,
-                    block_mode: Some(BlockMode::ECB),
-                    att_challenge: None,
-                    att_app_id: None,
-                },
-                KeyPurpose::DECRYPT,
-                ForcedOp(false),
-            );
-            assert!(result.is_ok());
-        } // End of digests.
-    } // End of key-sizes.
+    let alias = "ks_rsa_pss_none_key_op_test";
+    let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+            padding: Some(PaddingMode::RSA_PSS),
+            digest: Some(Digest::NONE),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: None,
+            att_app_id: None,
+        },
+        KeyPurpose::SIGN,
+        ForcedOp(false),
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
 }
 
 /// Generate RSA encryption key with -
@@ -412,122 +1578,28 @@
     let keystore2 = get_keystore_service();
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
-    let key_sizes = [2048, 3072, 4096];
+    let alias = "ks_rsa_key_oaep_padding_fail_test";
+    let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+            padding: Some(PaddingMode::RSA_OAEP),
+            digest: Some(Digest::NONE),
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: None,
+            att_app_id: None,
+        },
+        KeyPurpose::DECRYPT,
+        ForcedOp(false),
+    ));
 
-    for key_size in key_sizes {
-        let alias = format!("ks_rsa_key_padding_{}{}", getuid(), key_size);
-        let result = key_generations::map_ks_error(create_rsa_key_and_operation(
-            &sec_level,
-            Domain::APP,
-            -1,
-            Some(alias.to_string()),
-            &key_generations::KeyParams {
-                key_size,
-                purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
-                padding: Some(PaddingMode::RSA_OAEP),
-                digest: Some(Digest::NONE),
-                mgf_digest: None,
-                block_mode: None,
-                att_challenge: None,
-                att_app_id: None,
-            },
-            KeyPurpose::DECRYPT,
-            ForcedOp(false),
-        ));
-
-        assert!(result.is_err());
-        assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
-    }
-}
-
-/// Generate RSA encryption keys with various digest mode and padding mode combinations.
-///     Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-///     Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
-/// Try to create operations using generated keys, test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_keys_with_digest_paddings() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let digests = [
-        Digest::NONE,
-        Digest::MD5,
-        Digest::SHA1,
-        Digest::SHA_2_224,
-        Digest::SHA_2_256,
-        Digest::SHA_2_384,
-        Digest::SHA_2_512,
-    ];
-
-    let paddings = [PaddingMode::NONE, PaddingMode::RSA_PKCS1_1_5_ENCRYPT];
-
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        for digest in digests {
-            for padding in paddings {
-                let alias = format!("ks_rsa_key_padding_{}{}{}", getuid(), key_size, digest.0);
-                let result = key_generations::map_ks_error(create_rsa_key_and_operation(
-                    &sec_level,
-                    Domain::APP,
-                    -1,
-                    Some(alias.to_string()),
-                    &key_generations::KeyParams {
-                        key_size,
-                        purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
-                        padding: Some(padding),
-                        digest: Some(digest),
-                        mgf_digest: None,
-                        block_mode: None,
-                        att_challenge: None,
-                        att_app_id: None,
-                    },
-                    KeyPurpose::DECRYPT,
-                    ForcedOp(false),
-                ));
-
-                assert!(result.is_ok());
-            } // End of paddings.
-        } // End of digests.
-    } // End of key-sizes.
-}
-
-/// Generate RSA encryption keys with only padding modes.
-///     Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
-/// Try to create operations using generated keys, test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_keys_with_paddings() {
-    let keystore2 = get_keystore_service();
-    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
-    let paddings = [PaddingMode::NONE, PaddingMode::RSA_PKCS1_1_5_ENCRYPT];
-
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        for padding in paddings {
-            let alias = format!("ks_rsa_key_padding_{}{}", getuid(), key_size);
-            let result = create_rsa_key_and_operation(
-                &sec_level,
-                Domain::APP,
-                -1,
-                Some(alias.to_string()),
-                &key_generations::KeyParams {
-                    key_size,
-                    purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
-                    padding: Some(padding),
-                    digest: None,
-                    mgf_digest: None,
-                    block_mode: None,
-                    att_challenge: None,
-                    att_app_id: None,
-                },
-                KeyPurpose::DECRYPT,
-                ForcedOp(false),
-            );
-            assert!(result.is_ok());
-        } // End of paddings.
-    } // End of key-sizes.
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
 }
 
 /// Generate RSA keys without padding and digest modes. Try to create decrypt operation without
@@ -538,31 +1610,27 @@
     let keystore2 = get_keystore_service();
     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
 
-    let key_sizes = [2048, 3072, 4096];
-
-    for key_size in key_sizes {
-        let alias = format!("ks_rsa_key_test_{}{}", getuid(), key_size);
-        let result = key_generations::map_ks_error(create_rsa_key_and_operation(
-            &sec_level,
-            Domain::APP,
-            -1,
-            Some(alias.to_string()),
-            &key_generations::KeyParams {
-                key_size,
-                purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
-                padding: None,
-                digest: None,
-                mgf_digest: None,
-                block_mode: None,
-                att_challenge: None,
-                att_app_id: None,
-            },
-            KeyPurpose::DECRYPT,
-            ForcedOp(false),
-        ));
-        assert!(result.is_err());
-        assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
-    }
+    let alias = "ks_rsa_key_unsupport_padding_test";
+    let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+        &sec_level,
+        Domain::APP,
+        -1,
+        Some(alias.to_string()),
+        &key_generations::KeyParams {
+            key_size: 2048,
+            purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+            padding: None,
+            digest: None,
+            mgf_digest: None,
+            block_mode: None,
+            att_challenge: None,
+            att_app_id: None,
+        },
+        KeyPurpose::DECRYPT,
+        ForcedOp(false),
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
 }
 
 /// Generate a RSA encryption key. Try to create a signing operation with it, an error
@@ -665,7 +1733,7 @@
     let paddings = [PaddingMode::RSA_PKCS1_1_5_SIGN, PaddingMode::RSA_PSS];
 
     for padding in paddings {
-        let alias = format!("ks_rsa_key_test_4_{}{}", getuid(), padding.0);
+        let alias = format!("ks_rsa_encrypt_key_unsupported_pad_test{}", padding.0);
         let result = key_generations::map_ks_error(create_rsa_key_and_operation(
             &sec_level,
             Domain::APP,
@@ -699,7 +1767,7 @@
     let paddings = [PaddingMode::RSA_PKCS1_1_5_ENCRYPT, PaddingMode::RSA_OAEP];
 
     for padding in paddings {
-        let alias = format!("ks_rsa_key_test_4_{}{}", getuid(), padding.0);
+        let alias = format!("ks_rsa_sign_key_unsupported_pad_test_4_{}", padding.0);
         let result = key_generations::map_ks_error(create_rsa_key_and_operation(
             &sec_level,
             Domain::APP,
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 006f2f9..758e88b 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -15,6 +15,13 @@
 use nix::unistd::{Gid, Uid};
 use serde::{Deserialize, Serialize};
 
+use openssl::hash::MessageDigest;
+use openssl::rsa::Padding;
+use openssl::sign::Verifier;
+use openssl::x509::X509;
+
+use binder::wait_for_interface;
+
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     BlockMode::BlockMode, Digest::Digest, ErrorCode::ErrorCode,
     KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
@@ -23,9 +30,12 @@
 use android_system_keystore2::aidl::android::system::keystore2::{
     CreateOperationResponse::CreateOperationResponse, Domain::Domain,
     IKeystoreOperation::IKeystoreOperation, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
-    KeyDescriptor::KeyDescriptor, KeyParameters::KeyParameters, ResponseCode::ResponseCode,
+    IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor, KeyMetadata::KeyMetadata,
+    KeyParameters::KeyParameters, ResponseCode::ResponseCode,
 };
 
+use packagemanager_aidl::aidl::android::content::pm::IPackageManagerNative::IPackageManagerNative;
+
 use keystore2_test_utils::{
     authorizations, get_keystore_service, key_generations, key_generations::Error, run_as,
 };
@@ -50,6 +60,31 @@
 /// Sample plain text input for encrypt operation.
 pub const SAMPLE_PLAIN_TEXT: &[u8] = b"my message 11111";
 
+pub const PACKAGE_MANAGER_NATIVE_SERVICE: &str = "package_native";
+pub const APP_ATTEST_KEY_FEATURE: &str = "android.hardware.keystore.app_attest_key";
+
+/// Determines whether app_attest_key_feature is supported or not.
+pub fn app_attest_key_feature_exists() -> bool {
+    let pm = wait_for_interface::<dyn IPackageManagerNative>(PACKAGE_MANAGER_NATIVE_SERVICE)
+        .expect("Failed to get package manager native service.");
+
+    pm.hasSystemFeature(APP_ATTEST_KEY_FEATURE, 0).expect("hasSystemFeature failed.")
+}
+
+#[macro_export]
+macro_rules! skip_test_if_no_app_attest_key_feature {
+    () => {
+        if !app_attest_key_feature_exists() {
+            return;
+        }
+    };
+}
+
+pub fn has_trusty_keymint() -> bool {
+    binder::is_declared("android.hardware.security.keymint.IKeyMintDevice/default")
+        .expect("Could not check for declared keymint interface")
+}
+
 /// Generate a EC_P256 key using given domain, namespace and alias.
 /// Create an operation using the generated key and perform sample signing operation.
 pub fn create_signing_operation(
@@ -85,6 +120,104 @@
     Ok(())
 }
 
+/// Perform sample HMAC sign and verify operations.
+pub fn perform_sample_hmac_sign_verify_op(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    key: &KeyDescriptor,
+) {
+    let sign_op = sec_level
+        .createOperation(
+            key,
+            &authorizations::AuthSetBuilder::new()
+                .purpose(KeyPurpose::SIGN)
+                .digest(Digest::SHA_2_256)
+                .mac_length(256),
+            false,
+        )
+        .unwrap();
+    assert!(sign_op.iOperation.is_some());
+
+    let op = sign_op.iOperation.unwrap();
+    op.update(b"my message").unwrap();
+    let sig = op.finish(None, None).unwrap();
+    assert!(sig.is_some());
+
+    let sig = sig.unwrap();
+    let verify_op = sec_level
+        .createOperation(
+            key,
+            &authorizations::AuthSetBuilder::new()
+                .purpose(KeyPurpose::VERIFY)
+                .digest(Digest::SHA_2_256),
+            false,
+        )
+        .unwrap();
+    assert!(verify_op.iOperation.is_some());
+
+    let op = verify_op.iOperation.unwrap();
+    let result = op.finish(Some(b"my message"), Some(&sig)).unwrap();
+    assert!(result.is_none());
+}
+
+/// Map KeyMint Digest values to OpenSSL MessageDigest.
+pub fn get_openssl_digest_mode(digest: Option<Digest>) -> MessageDigest {
+    match digest {
+        Some(Digest::MD5) => MessageDigest::md5(),
+        Some(Digest::SHA1) => MessageDigest::sha1(),
+        Some(Digest::SHA_2_224) => MessageDigest::sha224(),
+        Some(Digest::SHA_2_256) => MessageDigest::sha256(),
+        Some(Digest::SHA_2_384) => MessageDigest::sha384(),
+        Some(Digest::SHA_2_512) => MessageDigest::sha512(),
+        _ => MessageDigest::sha256(),
+    }
+}
+
+/// Map KeyMint PaddingMode values to OpenSSL Padding.
+pub fn get_openssl_padding_mode(padding: PaddingMode) -> Padding {
+    match padding {
+        PaddingMode::RSA_OAEP => Padding::PKCS1_OAEP,
+        PaddingMode::RSA_PSS => Padding::PKCS1_PSS,
+        PaddingMode::RSA_PKCS1_1_5_SIGN => Padding::PKCS1,
+        PaddingMode::RSA_PKCS1_1_5_ENCRYPT => Padding::PKCS1,
+        _ => Padding::NONE,
+    }
+}
+
+/// Perform sample sign and verify operations using RSA or EC key.
+pub fn perform_sample_asym_sign_verify_op(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    key_metadata: &KeyMetadata,
+    padding: Option<PaddingMode>,
+    digest: Option<Digest>,
+) {
+    let mut authorizations = authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN);
+    if let Some(value) = padding {
+        authorizations = authorizations.padding_mode(value);
+    }
+    if let Some(value) = digest {
+        authorizations = authorizations.digest(value);
+    }
+
+    let sign_op = sec_level.createOperation(&key_metadata.key, &authorizations, false).unwrap();
+    assert!(sign_op.iOperation.is_some());
+
+    let op = sign_op.iOperation.unwrap();
+    op.update(b"my message").unwrap();
+    let sig = op.finish(None, None).unwrap();
+    assert!(sig.is_some());
+
+    let sig = sig.unwrap();
+    let cert_bytes = key_metadata.certificate.as_ref().unwrap();
+    let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+    let pub_key = cert.public_key().unwrap();
+    let mut verifier = Verifier::new(get_openssl_digest_mode(digest), pub_key.as_ref()).unwrap();
+    if let Some(value) = padding {
+        verifier.set_rsa_padding(get_openssl_padding_mode(value)).unwrap();
+    }
+    verifier.update(b"my message").unwrap();
+    assert!(verifier.verify(&sig).unwrap());
+}
+
 /// Create new operation on child proc and perform simple operation after parent notification.
 pub fn execute_op_run_as_child(
     target_ctx: &'static str,
@@ -202,3 +335,16 @@
     let op = op_response.iOperation.unwrap();
     op.finish(Some(input), None)
 }
+
+/// Delete a key with domain APP.
+pub fn delete_app_key(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    alias: &str,
+) -> binder::Result<()> {
+    keystore2.deleteKey(&KeyDescriptor {
+        domain: Domain::APP,
+        nspace: -1,
+        alias: Some(alias.to_string()),
+        blob: None,
+    })
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index b2257ed..41e3e36 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -14,9 +14,11 @@
 
 pub mod keystore2_client_3des_key_tests;
 pub mod keystore2_client_aes_key_tests;
+pub mod keystore2_client_attest_key_tests;
 pub mod keystore2_client_ec_key_tests;
 pub mod keystore2_client_grant_key_tests;
 pub mod keystore2_client_hmac_key_tests;
+pub mod keystore2_client_import_keys_tests;
 pub mod keystore2_client_key_id_domain_tests;
 pub mod keystore2_client_list_entries_tests;
 pub mod keystore2_client_operation_tests;
diff --git a/ondevice-signing/Android.bp b/ondevice-signing/Android.bp
index d73f8fe..f56cfab 100644
--- a/ondevice-signing/Android.bp
+++ b/ondevice-signing/Android.bp
@@ -101,6 +101,15 @@
   recovery_available: true,
 }
 
+genrule {
+  name: "statslog_odsign.h",
+  tools: ["stats-log-api-gen"],
+  cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_odsign.h --module art --namespace art,metrics,statsd",
+  out: [
+    "statslog_odsign.h",
+  ],
+}
+
 cc_binary {
   name: "odsign",
   defaults: [
@@ -114,6 +123,7 @@
     "odsign_main.cpp",
     "StatsReporter.cpp",
   ],
+  generated_headers: ["statslog_odsign.h"],
 
   header_libs: ["odrefresh_headers"],
 
diff --git a/ondevice-signing/StatsReporter.cpp b/ondevice-signing/StatsReporter.cpp
index 65e645a..e4e4a03 100644
--- a/ondevice-signing/StatsReporter.cpp
+++ b/ondevice-signing/StatsReporter.cpp
@@ -20,12 +20,13 @@
 #include <string>
 #include <sys/stat.h>
 
-// Keep these constant in sync with COMPOS_METRIC_NAME & METRICS_FILE in OdsignStatsLogger.java.
+// Keep these constants in sync with those in OdsignStatsLogger.java.
 constexpr const char* kOdsignMetricsFile = "/data/misc/odsign/metrics/odsign-metrics.txt";
 constexpr const char* kComposMetricName = "comp_os_artifacts_check_record";
+constexpr const char* kOdsignMetricName = "odsign_record";
 
 StatsReporter::~StatsReporter() {
-    if (comp_os_artifacts_check_record_ == nullptr) {
+    if (comp_os_artifacts_check_record_ == nullptr && !odsign_record_enabled_) {
         LOG(INFO) << "Metrics report is empty";
 
         // Remove the metrics file if any old version of the file already exists
@@ -42,24 +43,31 @@
         PLOG(ERROR) << "Could not open file: " << kOdsignMetricsFile;
         return;
     }
-
-    odsign_metrics_file_ << kComposMetricName << ' ';
-    odsign_metrics_file_ << comp_os_artifacts_check_record_->current_artifacts_ok << ' ';
-    odsign_metrics_file_ << comp_os_artifacts_check_record_->comp_os_pending_artifacts_exists
-                         << ' ';
-    odsign_metrics_file_ << comp_os_artifacts_check_record_->use_comp_os_generated_artifacts
-                         << '\n';
     if (chmod(kOdsignMetricsFile, 0644) != 0) {
         PLOG(ERROR) << "Could not set correct file permissions for " << kOdsignMetricsFile;
         return;
     }
+
+    if (comp_os_artifacts_check_record_ != nullptr) {
+        odsign_metrics_file_ << kComposMetricName << ' '
+                             << comp_os_artifacts_check_record_->current_artifacts_ok << ' '
+                             << comp_os_artifacts_check_record_->comp_os_pending_artifacts_exists
+                             << ' '
+                             << comp_os_artifacts_check_record_->use_comp_os_generated_artifacts
+                             << '\n';
+    }
+
+    if (odsign_record_enabled_) {
+        odsign_metrics_file_ << kOdsignMetricName << ' ' << odsign_record_.status << '\n';
+    }
+
     odsign_metrics_file_.close();
     if (!odsign_metrics_file_) {
         PLOG(ERROR) << "Failed to close the file";
     }
 }
 
-StatsReporter::CompOsArtifactsCheckRecord* StatsReporter::GetComposArtifactsCheckRecord() {
+StatsReporter::CompOsArtifactsCheckRecord* StatsReporter::GetOrCreateComposArtifactsCheckRecord() {
     if (comp_os_artifacts_check_record_ == nullptr) {
         comp_os_artifacts_check_record_ = std::make_unique<CompOsArtifactsCheckRecord>();
     }
diff --git a/ondevice-signing/StatsReporter.h b/ondevice-signing/StatsReporter.h
index 2682b96..add7a11 100644
--- a/ondevice-signing/StatsReporter.h
+++ b/ondevice-signing/StatsReporter.h
@@ -18,27 +18,44 @@
 
 #include <fstream>
 
+#include "statslog_odsign.h"
+
 // Class to store CompOsArtifactsCheck related metrics.
 // These are flushed to a file kOdsignMetricsFile and consumed by
 // System Server (in class OdsignStatsLogger) & sent to statsd.
 class StatsReporter {
   public:
-    // Keep sync with EarlyBootCompOsArtifactsCheckReported
-    // definition in proto_logging/stats/atoms.proto.
+    // Keep in sync with the EarlyBootCompOsArtifactsCheckReported definition in
+    // proto_logging/stats/atoms.proto.
     struct CompOsArtifactsCheckRecord {
         bool current_artifacts_ok = false;
         bool comp_os_pending_artifacts_exists = false;
         bool use_comp_os_generated_artifacts = false;
     };
 
+    // Keep in sync with the OdsignReported definition in proto_logging/stats/atoms.proto.
+    struct OdsignRecord {
+        int32_t status = art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_UNSPECIFIED;
+    };
+
     // The report is flushed (from buffer) into a file by the destructor.
     ~StatsReporter();
 
-    // Get pointer to comp_os_artifacts_check_record, caller can then modify it.
-    // Note: pointer remains valid for the lifetime of this StatsReporter.
-    CompOsArtifactsCheckRecord* GetComposArtifactsCheckRecord();
+    // Returns a mutable CompOS record. The pointer remains valid for the lifetime of this
+    // StatsReporter. If this function is not called, no CompOS record will be logged.
+    CompOsArtifactsCheckRecord* GetOrCreateComposArtifactsCheckRecord();
+
+    // Returns a mutable odsign record. The pointer remains valid for the lifetime of this
+    // StatsReporter.
+    OdsignRecord* GetOdsignRecord() { return &odsign_record_; }
+
+    // Enables/disables odsign metrics.
+    void SetOdsignRecordEnabled(bool value) { odsign_record_enabled_ = value; }
 
   private:
     // Temporary buffer which stores the metrics.
     std::unique_ptr<CompOsArtifactsCheckRecord> comp_os_artifacts_check_record_;
+
+    OdsignRecord odsign_record_;
+    bool odsign_record_enabled_ = true;
 };
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index cd9a1ea..d5c7299 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#include "android-base/errors.h"
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
@@ -127,20 +128,6 @@
     }
 };
 
-static Result<void> measureFsVerity(int fd, const fsverity_digest* digest) {
-    if (ioctl(fd, FS_IOC_MEASURE_VERITY, digest) != 0) {
-        if (errno == ENODATA) {
-            return Error() << "File is not in fs-verity";
-        } else {
-            return ErrnoError() << "Failed to FS_IOC_MEASURE_VERITY";
-        }
-    }
-
-    return {};
-}
-
-}  // namespace
-
 template <typename T> using trailing_unique_ptr = std::unique_ptr<T, DeleteAsPODArray<T>>;
 
 template <typename T>
@@ -150,6 +137,32 @@
     return trailing_unique_ptr<T>{ptr};
 }
 
+static Result<std::string> measureFsVerity(int fd) {
+    auto d = makeUniqueWithTrailingData<fsverity_digest>(FS_VERITY_MAX_DIGEST_SIZE);
+    d->digest_size = FS_VERITY_MAX_DIGEST_SIZE;
+
+    if (ioctl(fd, FS_IOC_MEASURE_VERITY, d.get()) != 0) {
+        if (errno == ENODATA) {
+            return Error() << "File is not in fs-verity";
+        } else {
+            return ErrnoError() << "Failed to FS_IOC_MEASURE_VERITY";
+        }
+    }
+
+    return toHex({&d->digest[0], &d->digest[d->digest_size]});
+}
+
+static Result<std::string> measureFsVerity(const std::string& path) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (!fd.ok()) {
+        return ErrnoError() << "Failed to open " << path;
+    }
+
+    return measureFsVerity(fd.get());
+}
+
+}  // 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());
@@ -209,30 +222,12 @@
     return toHex(digest.value());
 }
 
-static Result<std::string> isFileInVerity(int fd) {
-    auto d = makeUniqueWithTrailingData<fsverity_digest>(FS_VERITY_MAX_DIGEST_SIZE);
-    d->digest_size = FS_VERITY_MAX_DIGEST_SIZE;
-
-    const auto& status = measureFsVerity(fd, d.get());
-    if (!status.ok()) {
-        return status.error();
+static Result<bool> isFileInVerity(int fd) {
+    unsigned int flags;
+    if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0) {
+        return ErrnoError() << "ioctl(FS_IOC_GETFLAGS) failed";
     }
-
-    return toHex({&d->digest[0], &d->digest[d->digest_size]});
-}
-
-static Result<std::string> isFileInVerity(const std::string& path) {
-    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (!fd.ok()) {
-        return ErrnoError() << "Failed to open " << path;
-    }
-
-    auto digest = isFileInVerity(fd.get());
-    if (!digest.ok()) {
-        return Error() << digest.error() << ": " << path;
-    }
-
-    return digest;
+    return (flags & FS_VERITY_FL) != 0;
 }
 
 Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path,
@@ -247,18 +242,15 @@
             if (!fd.ok()) {
                 return ErrnoError() << "Failed to open " << path;
             }
-            auto digest = isFileInVerity(fd);
-            if (!digest.ok()) {
+            auto enabled = OR_RETURN(isFileInVerity(fd));
+            if (!enabled) {
                 LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
-                auto result = enableFsVerity(fd, key);
-                if (!result.ok()) {
-                    return result.error();
-                }
-                digests[it->path()] = *result;
+                OR_RETURN(enableFsVerity(fd, key));
             } else {
                 LOG(INFO) << it->path() << " was already in fs-verity.";
-                digests[it->path()] = *digest;
             }
+            auto digest = OR_RETURN(measureFsVerity(fd));
+            digests[it->path()] = digest;
         }
     }
     if (ec) {
@@ -282,14 +274,6 @@
     if (!enable.ok()) {
         return enable.error();
     }
-
-    auto digest = makeUniqueWithTrailingData<fsverity_digest>(FS_VERITY_MAX_DIGEST_SIZE);
-    digest->digest_size = FS_VERITY_MAX_DIGEST_SIZE;
-    const auto& measure = measureFsVerity(fd.get(), digest.get());
-    if (!measure.ok()) {
-        return measure.error();
-    }
-
     return {};
 }
 
@@ -303,11 +287,8 @@
     while (!ec && it != end) {
         if (it->is_regular_file()) {
             // Verify the file is in fs-verity
-            auto result = isFileInVerity(it->path());
-            if (!result.ok()) {
-                return result.error();
-            }
-            digests[it->path()] = *result;
+            auto result = OR_RETURN(measureFsVerity(it->path()));
+            digests[it->path()] = result;
         } else if (it->is_directory()) {
             // These are fine to ignore
         } else if (it->is_symlink()) {
@@ -344,7 +325,7 @@
                 return ErrnoError() << "Can't open " << path;
             }
 
-            auto verity_digest = isFileInVerity(fd);
+            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.
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index c45e308..93ec3e4 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -35,6 +35,7 @@
 #include "KeystoreKey.h"
 #include "StatsReporter.h"
 #include "VerityUtils.h"
+#include "statslog_odsign.h"
 
 #include "odsign_info.pb.h"
 
@@ -370,7 +371,7 @@
                                                      bool* digests_verified,
                                                      StatsReporter* stats_reporter) {
     StatsReporter::CompOsArtifactsCheckRecord* compos_check_record =
-        stats_reporter->GetComposArtifactsCheckRecord();
+        stats_reporter->GetOrCreateComposArtifactsCheckRecord();
 
     if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
         // No pending CompOS artifacts, all that matters is the current ones.
@@ -468,12 +469,9 @@
 }  // namespace
 
 int main(int /* argc */, char** argv) {
-    // stats_reporter is a pointer so that we can explicitly delete it
-    // instead of waiting for the program to die & its destrcutor be called
-    auto stats_reporter = std::make_unique<StatsReporter>();
     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
 
-    auto errorScopeGuard = []() {
+    auto scope_guard = android::base::make_scope_guard([]() {
         // In case we hit any error, remove the artifacts and tell Zygote not to use
         // anything
         removeDirectory(kArtArtifactsDir);
@@ -485,17 +483,24 @@
         SetProperty(kOdsignVerificationDoneProp, "1");
         // Tell init it shouldn't try to restart us - see odsign.rc
         SetProperty(kStopServiceProp, "odsign");
-    };
-    auto scope_guard = android::base::make_scope_guard(errorScopeGuard);
+    });
+
+    // `stats_reporter` must come after `scope_guard` so that its destructor is called before
+    // `scope_guard`.
+    auto stats_reporter = std::make_unique<StatsReporter>();
+    StatsReporter::OdsignRecord* odsign_record = stats_reporter->GetOdsignRecord();
 
     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
         LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
+        stats_reporter->SetOdsignRecordEnabled(false);
         return 0;
     }
     auto keystoreResult =
         KeystoreKey::getInstance(kPublicKeySignature, kKeyAlias, kKeyNspace, kKeyBootLevel);
     if (!keystoreResult.ok()) {
         LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error();
+        odsign_record->status =
+            art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_KEYSTORE_FAILED;
         return -1;
     }
     SigningKey* key = keystoreResult.value();
@@ -517,6 +522,8 @@
             if (!new_cert.ok()) {
                 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error();
                 // TODO apparently the key become invalid - delete the blob / cert
+                odsign_record->status =
+                    art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CERT_FAILED;
                 return -1;
             }
         } else {
@@ -526,6 +533,8 @@
         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;
         }
     }
@@ -535,12 +544,6 @@
         useCompOs ? CheckCompOsPendingArtifacts(*key, &digests_verified, stats_reporter.get())
                   : checkArtifacts();
 
-    // Explicitly reset the pointer - We rely on stats_reporter's
-    // destructor for actually writing the buffered metrics. This will otherwise not be called
-    // if the program doesn't exit normally (for ex, killed by init, which actually happens
-    // because odsign (after it finishes) sets kStopServiceProp instructing init to kill it).
-    stats_reporter.reset();
-
     // The artifacts dir doesn't necessarily need to exist; if the existing
     // artifacts on the system partition are valid, those can be used.
     int err = access(kArtArtifactsDir.c_str(), F_OK);
@@ -578,6 +581,8 @@
                 // instead prevent Zygote from using them (which is taken care of
                 // in the exit handler).
                 LOG(ERROR) << "Failed to remove unknown artifacts.";
+                odsign_record->status =
+                    art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CLEANUP_FAILED;
                 return -1;
             }
         }
@@ -591,11 +596,16 @@
     if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
         // No new artifacts generated, and we verified existing ones above, nothing left to do.
         LOG(INFO) << "odrefresh said artifacts are VALID";
+        stats_reporter->SetOdsignRecordEnabled(false);
     } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
                odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
         const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;
         LOG(INFO) << "odrefresh compiled " << (compiled_all ? "all" : "partial")
                   << " artifacts, returned " << odrefresh_status;
+        // This value may be overwritten later.
+        odsign_record->status =
+            compiled_all ? art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ALL_OK
+                         : art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_PARTIAL_OK;
         Result<std::map<std::string, std::string>> digests;
         if (supportsFsVerity) {
             digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
@@ -606,24 +616,39 @@
         }
         if (!digests.ok()) {
             LOG(ERROR) << digests.error();
+            odsign_record->status =
+                art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_SIGNING_FAILED;
             return -1;
         }
         auto persistStatus = persistDigests(*digests, *key);
         if (!persistStatus.ok()) {
             LOG(ERROR) << persistStatus.error();
+            odsign_record->status =
+                art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_SIGNING_FAILED;
             return -1;
         }
     } else if (odrefresh_status == art::odrefresh::ExitCode::kCleanupFailed) {
         LOG(ERROR) << "odrefresh failed cleaning up existing artifacts";
+        odsign_record->status =
+            art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ODREFRESH_FAILED;
         return -1;
     } else {
         LOG(ERROR) << "odrefresh exited unexpectedly, returned " << odrefresh_status;
+        odsign_record->status =
+            art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ODREFRESH_FAILED;
         return -1;
     }
 
     LOG(INFO) << "On-device signing done.";
 
     scope_guard.Disable();
+
+    // Explicitly reset the pointer - We rely on stats_reporter's
+    // destructor for actually writing the buffered metrics. This will otherwise not be called
+    // if the program doesn't exit normally (for ex, killed by init, which actually happens
+    // because odsign (after it finishes) sets kStopServiceProp instructing init to kill it).
+    stats_reporter.reset();
+
     // At this point, we're done with the key for sure
     SetProperty(kOdsignKeyDoneProp, "1");
     // And we did a successful verification
diff --git a/prng_seeder/Android.bp b/prng_seeder/Android.bp
index 47e7bbe..5759731 100644
--- a/prng_seeder/Android.bp
+++ b/prng_seeder/Android.bp
@@ -14,9 +14,6 @@
 
 package {
     // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "external_boringssl_license"
-    // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["system_security_license"],
 }
diff --git a/prng_seeder/OWNERS b/prng_seeder/OWNERS
new file mode 100644
index 0000000..9202b90
--- /dev/null
+++ b/prng_seeder/OWNERS
@@ -0,0 +1,2 @@
+paulcrowley@google.com
+prb@google.com
\ No newline at end of file
diff --git a/prng_seeder/src/conditioner.rs b/prng_seeder/src/conditioner.rs
index 66b29a4..eca8af8 100644
--- a/prng_seeder/src/conditioner.rs
+++ b/prng_seeder/src/conditioner.rs
@@ -12,10 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use std::{fs::File, io::Read};
+use std::{fs::File, io::Read, os::unix::io::AsRawFd};
 
-use anyhow::{ensure, Result};
+use anyhow::{ensure, Context, Result};
 use log::debug;
+use nix::fcntl::{fcntl, FcntlArg::F_SETFL, OFlag};
 use tokio::io::AsyncReadExt;
 
 use crate::drbg;
@@ -23,6 +24,30 @@
 const SEED_FOR_CLIENT_LEN: usize = 496;
 const NUM_REQUESTS_PER_RESEED: u32 = 256;
 
+pub struct ConditionerBuilder {
+    hwrng: File,
+    rg: drbg::Drbg,
+}
+
+impl ConditionerBuilder {
+    pub fn new(mut hwrng: File) -> Result<ConditionerBuilder> {
+        let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
+        hwrng.read_exact(&mut et).context("hwrng.read_exact in new")?;
+        let rg = drbg::Drbg::new(&et)?;
+        fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK))
+            .context("setting O_NONBLOCK on hwrng")?;
+        Ok(ConditionerBuilder { hwrng, rg })
+    }
+
+    pub fn build(self) -> Conditioner {
+        Conditioner {
+            hwrng: tokio::fs::File::from_std(self.hwrng),
+            rg: self.rg,
+            requests_since_reseed: 0,
+        }
+    }
+}
+
 pub struct Conditioner {
     hwrng: tokio::fs::File,
     rg: drbg::Drbg,
@@ -30,18 +55,11 @@
 }
 
 impl Conditioner {
-    pub fn new(mut hwrng: File) -> Result<Conditioner> {
-        let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
-        hwrng.read_exact(&mut et)?;
-        let rg = drbg::Drbg::new(&et)?;
-        Ok(Conditioner { hwrng: tokio::fs::File::from_std(hwrng), rg, requests_since_reseed: 0 })
-    }
-
     pub async fn reseed_if_necessary(&mut self) -> Result<()> {
         if self.requests_since_reseed >= NUM_REQUESTS_PER_RESEED {
             debug!("Reseeding DRBG");
             let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
-            self.hwrng.read_exact(&mut et).await?;
+            self.hwrng.read_exact(&mut et).await.context("hwrng.read_exact in reseed")?;
             self.rg.reseed(&et)?;
             self.requests_since_reseed = 0;
         }
diff --git a/prng_seeder/src/main.rs b/prng_seeder/src/main.rs
index fe11134..3f698f6 100644
--- a/prng_seeder/src/main.rs
+++ b/prng_seeder/src/main.rs
@@ -23,22 +23,19 @@
 
 use std::{
     convert::Infallible,
-    fs::{remove_file, File},
+    fs::remove_file,
     io::ErrorKind,
-    os::unix::{net::UnixListener, prelude::AsRawFd},
+    os::unix::net::UnixListener,
     path::{Path, PathBuf},
 };
 
-use anyhow::Result;
+use anyhow::{ensure, Context, Result};
 use clap::Parser;
-use log::{error, info};
-use nix::{
-    fcntl::{fcntl, FcntlArg::F_SETFL, OFlag},
-    sys::signal,
-};
+use log::{error, info, Level};
+use nix::sys::signal;
 use tokio::{io::AsyncWriteExt, net::UnixListener as TokioUnixListener};
 
-use crate::conditioner::Conditioner;
+use crate::conditioner::ConditionerBuilder;
 
 #[derive(Debug, clap::Parser)]
 struct Cli {
@@ -48,24 +45,50 @@
     socket: Option<PathBuf>,
 }
 
-fn configure_logging() {
-    logger::init(Default::default());
+fn configure_logging() -> Result<()> {
+    ensure!(
+        logger::init(
+            logger::Config::default().with_tag_on_device("prng_seeder").with_min_level(Level::Info)
+        ),
+        "log configuration failed"
+    );
+    Ok(())
 }
 
 fn get_socket(path: &Path) -> Result<UnixListener> {
     if let Err(e) = remove_file(path) {
         if e.kind() != ErrorKind::NotFound {
-            return Err(e.into());
+            return Err(e).context(format!("Removing old socket: {}", path.display()));
         }
     } else {
-        info!("Deleted old {}", path.to_string_lossy());
+        info!("Deleted old {}", path.display());
     }
-    Ok(UnixListener::bind(path)?)
+    UnixListener::bind(path)
+        .with_context(|| format!("In get_socket: binding socket to {}", path.display()))
 }
 
-async fn listen_loop(hwrng: File, listener: UnixListener) -> Result<Infallible> {
-    let mut conditioner = Conditioner::new(hwrng)?;
-    let listener = TokioUnixListener::from_std(listener)?;
+fn setup() -> Result<(ConditionerBuilder, UnixListener)> {
+    configure_logging()?;
+    let cli = Cli::try_parse()?;
+    unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }
+        .context("In setup, setting SIGPIPE to SIG_IGN")?;
+
+    let listener = match cli.socket {
+        Some(path) => get_socket(path.as_path())?,
+        None => cutils_socket::android_get_control_socket("prng_seeder")
+            .context("In setup, calling android_get_control_socket")?,
+    };
+    let hwrng = std::fs::File::open(&cli.source)
+        .with_context(|| format!("Unable to open hwrng {}", cli.source.display()))?;
+    let cb = ConditionerBuilder::new(hwrng)?;
+    Ok((cb, listener))
+}
+
+async fn listen_loop(cb: ConditionerBuilder, listener: UnixListener) -> Result<Infallible> {
+    let mut conditioner = cb.build();
+    listener.set_nonblocking(true).context("In listen_loop, on set_nonblocking")?;
+    let listener = TokioUnixListener::from_std(listener).context("In listen_loop, on from_std")?;
+    info!("Starting listen loop");
     loop {
         match listener.accept().await {
             Ok((mut stream, _)) => {
@@ -78,35 +101,37 @@
                 conditioner.reseed_if_necessary().await?;
             }
             Err(e) if e.kind() == ErrorKind::Interrupted => {}
-            Err(e) => return Err(e.into()),
+            Err(e) => return Err(e).context("accept on socket failed"),
         }
     }
 }
 
-fn run(cli: Cli) -> Result<Infallible> {
-    let hwrng = std::fs::File::open(&cli.source)?;
-    fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK))?;
-    let listener = match cli.socket {
-        Some(path) => get_socket(path.as_path())?,
-        None => cutils_socket::android_get_control_socket("prng_seeder")?,
+fn run() -> Result<Infallible> {
+    let (cb, listener) = match setup() {
+        Ok(t) => t,
+        Err(e) => {
+            // If setup fails, just hang forever. That way init doesn't respawn us.
+            error!("Hanging forever because setup failed: {:?}", e);
+            // Logs are sometimes mysteriously not being logged, so print too
+            println!("prng_seeder: Hanging forever because setup failed: {:?}", e);
+            loop {
+                std::thread::park();
+                error!("std::thread::park() finished unexpectedly, re-parking thread");
+            }
+        }
     };
-    listener.set_nonblocking(true)?;
-
-    unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }?;
 
     tokio::runtime::Builder::new_current_thread()
         .enable_all()
-        .build()?
-        .block_on(async { listen_loop(hwrng, listener).await })
+        .build()
+        .context("In run, building reactor")?
+        .block_on(async { listen_loop(cb, listener).await })
 }
 
 fn main() {
-    let cli = Cli::parse();
-    configure_logging();
-    if let Err(e) = run(cli) {
-        error!("Launch failed: {}", e);
-    } else {
-        error!("Loop terminated without an error")
-    }
+    let e = run();
+    error!("Launch terminated: {:?}", e);
+    // Logs are sometimes mysteriously not being logged, so print too
+    println!("prng_seeder: launch terminated: {:?}", e);
     std::process::exit(-1);
 }
diff --git a/provisioner/Android.bp b/provisioner/Android.bp
index 87f39d0..b548973 100644
--- a/provisioner/Android.bp
+++ b/provisioner/Android.bp
@@ -55,6 +55,7 @@
         "liblog",
     ],
     static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "libbase",
         "libcppbor_external",
         "libcppcose_rkp",
diff --git a/provisioner/rkp_factory_extraction_lib.cpp b/provisioner/rkp_factory_extraction_lib.cpp
index 77d032b..d85e85f 100644
--- a/provisioner/rkp_factory_extraction_lib.cpp
+++ b/provisioner/rkp_factory_extraction_lib.cpp
@@ -46,11 +46,14 @@
 using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
 using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
 using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateFactoryDeviceInfo;
+using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryCsr;
 using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryProtectedData;
 
 using namespace cppbor;
 using namespace cppcose;
 
+constexpr size_t kVersionWithoutSuperencryption = 3;
+
 std::string toBase64(const std::vector<uint8_t>& buffer) {
     size_t base64Length;
     int rc = EVP_EncodedLength(&base64Length, buffer.size());
@@ -97,11 +100,11 @@
     return challenge;
 }
 
-CborResult<Array> composeCertificateRequest(const ProtectedData& protectedData,
-                                            const DeviceInfo& verifiedDeviceInfo,
-                                            const std::vector<uint8_t>& challenge,
-                                            const std::vector<uint8_t>& keysToSignMac,
-                                            IRemotelyProvisionedComponent* provisionable) {
+CborResult<Array> composeCertificateRequestV1(const ProtectedData& protectedData,
+                                              const DeviceInfo& verifiedDeviceInfo,
+                                              const std::vector<uint8_t>& challenge,
+                                              const std::vector<uint8_t>& keysToSignMac,
+                                              IRemotelyProvisionedComponent* provisionable) {
     Array macedKeysToSign = Array()
                                 .add(Map().add(1, 5).encode())  // alg: hmac-sha256
                                 .add(Map())                     // empty unprotected headers
@@ -131,7 +134,7 @@
     return {std::move(certificateRequest), ""};
 }
 
-CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+CborResult<Array> getCsrV1(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
     std::vector<uint8_t> keysToSignMac;
     std::vector<MacedPublicKey> emptyKeys;
     DeviceInfo verifiedDeviceInfo;
@@ -154,11 +157,11 @@
                   << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
         exit(-1);
     }
-    return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
-                                     irpc);
+    return composeCertificateRequestV1(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
+                                       irpc);
 }
 
-void selfTestGetCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+void selfTestGetCsrV1(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
     std::vector<uint8_t> keysToSignMac;
     std::vector<MacedPublicKey> emptyKeys;
     DeviceInfo verifiedDeviceInfo;
@@ -192,4 +195,86 @@
                                              hwInfo.supportedEekCurve, irpc, challenge);
 
     std::cout << "Self test successful." << std::endl;
-}
\ No newline at end of file
+}
+
+CborResult<Array> composeCertificateRequestV3(const std::vector<uint8_t>& csr) {
+    auto [parsedCsr, _, csrErrMsg] = cppbor::parse(csr);
+    if (!parsedCsr) {
+        return {nullptr, csrErrMsg};
+    }
+    if (!parsedCsr->asArray()) {
+        return {nullptr, "CSR is not a CBOR array."};
+    }
+
+    return {std::unique_ptr<Array>(parsedCsr.release()->asArray()), ""};
+}
+
+CborResult<cppbor::Array> getCsrV3(std::string_view componentName,
+                                   IRemotelyProvisionedComponent* irpc) {
+    std::vector<uint8_t> csr;
+    std::vector<MacedPublicKey> emptyKeys;
+    const std::vector<uint8_t> challenge = generateChallenge();
+
+    auto status = irpc->generateCertificateRequestV2(emptyKeys, challenge, &csr);
+    if (!status.isOk()) {
+        std::cerr << "Bundle extraction failed for '" << componentName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+
+    return composeCertificateRequestV3(csr);
+}
+
+void selfTestGetCsrV3(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+    std::vector<uint8_t> csr;
+    std::vector<MacedPublicKey> emptyKeys;
+    const std::vector<uint8_t> challenge = generateChallenge();
+
+    auto status = irpc->generateCertificateRequestV2(emptyKeys, challenge, &csr);
+    if (!status.isOk()) {
+        std::cerr << "Bundle extraction failed for '" << componentName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+
+    auto result = verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge);
+    if (!result) {
+        std::cerr << "Self test failed for '" << componentName
+                  << "'. Error message: " << result.message() << "." << std::endl;
+        exit(-1);
+    }
+
+    std::cout << "Self test successful." << std::endl;
+}
+
+CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+    RpcHardwareInfo hwInfo;
+    auto status = irpc->getHardwareInfo(&hwInfo);
+    if (!status.isOk()) {
+        std::cerr << "Failed to get hardware info for '" << componentName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+
+    if (hwInfo.versionNumber < kVersionWithoutSuperencryption) {
+        return getCsrV1(componentName, irpc);
+    } else {
+        return getCsrV3(componentName, irpc);
+    }
+}
+
+void selfTestGetCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+    RpcHardwareInfo hwInfo;
+    auto status = irpc->getHardwareInfo(&hwInfo);
+    if (!status.isOk()) {
+        std::cerr << "Failed to get hardware info for '" << componentName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+
+    if (hwInfo.versionNumber < kVersionWithoutSuperencryption) {
+        selfTestGetCsrV1(componentName, irpc);
+    } else {
+        selfTestGetCsrV3(componentName, irpc);
+    }
+}
diff --git a/provisioner/rkp_factory_extraction_lib.h b/provisioner/rkp_factory_extraction_lib.h
index a803582..a218338 100644
--- a/provisioner/rkp_factory_extraction_lib.h
+++ b/provisioner/rkp_factory_extraction_lib.h
@@ -25,7 +25,8 @@
 #include <string_view>
 #include <vector>
 
-constexpr size_t kChallengeSize = 16;
+// Challenge size must be between 32 and 64 bytes inclusive.
+constexpr size_t kChallengeSize = 64;
 
 // Contains a the result of an operation that should return cborData on success.
 // Returns an an error message and null cborData on error.
@@ -50,4 +51,4 @@
 // Generates a test certificate chain and validates it, exiting the process on error.
 void selfTestGetCsr(
     std::string_view componentName,
-    aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
\ No newline at end of file
+    aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
diff --git a/provisioner/rkp_factory_extraction_lib_test.cpp b/provisioner/rkp_factory_extraction_lib_test.cpp
index b27b717..05509b3 100644
--- a/provisioner/rkp_factory_extraction_lib_test.cpp
+++ b/provisioner/rkp_factory_extraction_lib_test.cpp
@@ -72,6 +72,10 @@
                  const std::vector<uint8_t>& in_challenge, DeviceInfo* out_deviceInfo,
                  ProtectedData* out_protectedData, std::vector<uint8_t>* _aidl_return),
                 (override));
+    MOCK_METHOD(ScopedAStatus, generateCertificateRequestV2,
+                (const std::vector<MacedPublicKey>& in_keysToSign,
+                 const std::vector<uint8_t>& in_challenge, std::vector<uint8_t>* _aidl_return),
+                (override));
     MOCK_METHOD(ScopedAStatus, getInterfaceVersion, (int32_t * _aidl_return), (override));
     MOCK_METHOD(ScopedAStatus, getInterfaceHash, (std::string * _aidl_return), (override));
 };
@@ -221,3 +225,35 @@
     EXPECT_THAT(actualMacedKeys->get(2)->asNull(), NotNull());
     EXPECT_THAT(actualMacedKeys->get(3)->asBstr(), Pointee(Eq(Bstr(kFakeMac))));
 }
+
+TEST(LibRkpFactoryExtractionTests, GetCsrWithV3Hal) {
+    const std::vector<uint8_t> kCsr = Array()
+                                          .add(3 /* version */)
+                                          .add(Map() /* UdsCerts */)
+                                          .add(Array() /* DiceCertChain */)
+                                          .add(Array() /* SignedData */)
+                                          .encode();
+    std::vector<uint8_t> challenge;
+
+    // Set up mock, then call getCsr
+    auto mockRpc = SharedRefBase::make<MockIRemotelyProvisionedComponent>();
+    EXPECT_CALL(*mockRpc, getHardwareInfo(NotNull())).WillRepeatedly([](RpcHardwareInfo* hwInfo) {
+        hwInfo->versionNumber = 3;
+        return ScopedAStatus::ok();
+    });
+    EXPECT_CALL(*mockRpc,
+                generateCertificateRequestV2(IsEmpty(),   // keysToSign
+                                             _,           // challenge
+                                             NotNull()))  // _aidl_return
+        .WillOnce(DoAll(SaveArg<1>(&challenge), SetArgPointee<2>(kCsr),
+                        Return(ByMove(ScopedAStatus::ok()))));
+
+    auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get());
+    ASSERT_THAT(csr, NotNull()) << csrErrMsg;
+    ASSERT_THAT(csr, Pointee(Property(&Array::size, Eq(4))));
+
+    EXPECT_THAT(csr->get(0 /* version */), Pointee(Eq(Uint(3))));
+    EXPECT_THAT(csr->get(1)->asMap(), NotNull());
+    EXPECT_THAT(csr->get(2)->asArray(), NotNull());
+    EXPECT_THAT(csr->get(3)->asArray(), NotNull());
+}
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 0fe7d74..2aeabe0 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -47,8 +47,6 @@
 constexpr std::string_view kBuildPlusCsr = "build+csr";  // Text-encoded (JSON) build
                                                          // fingerprint plus CSR.
 
-constexpr size_t kChallengeSize = 16;
-
 void writeOutput(const std::string instance_name, const Array& csr) {
     if (FLAGS_output_format == kBinaryCsrOutput) {
         auto bytes = csr.encode();