KeyStore: use security level to chose keymaster device

Keymaster4 introduces security levels. Android devices
may have multiple keymaster implementations, one for each
possible security level, where the presence of a strong
security level implies the presence of all lower levels.

This patch adds code that enumerates all keymaster device
implementations available from ServiceManager and populates
Keystore's keymaster device database with at most one keymaster
implementation per security level. It gives precedence to
newer versions if multiple implementations exist for the same security
level.

The security level is chosen by a set of flags passed to the keystore
operations generate, import, addRngEntropy.
For existing keys the right security level is chosen by the blob flags.

To that end a new flag KEYSTORE_FLAG_STRONGBOX was added, and the
security level is expressed through a combination of
KEYSTORE_FLAG_FALLBACK (F) and KEYSTORE_FLAG_STRONGBOX (S).
Encoding is as follows:

             F     S
Software     1     X (don't care)
TEE          0     0
Strongbox    0     1

Some operations in keystore cli2 where amended with the optional
--seclevel flags. Allowing the user to chose the security level for the
given operation. Possible options are "software", "strongbox", and "tee"
where tee is the default value.

Test: Existing KeyStore CTS tests run

Change-Id: I01ef238f5e7067e480cf9b171630237236046bb1
diff --git a/keystore/Android.bp b/keystore/Android.bp
index 565351d..de11ec6 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -23,6 +23,7 @@
         ":IKeyAttestationApplicationIdProvider.aidl",
         "KeyStore.cpp",
         "Keymaster3.cpp",
+        "Keymaster4.cpp",
         "auth_token_table.cpp",
         "blob.cpp",
         "entropy.cpp",
diff --git a/keystore/KeyStore.cpp b/keystore/KeyStore.cpp
index fd5b26d..d9355b9 100644
--- a/keystore/KeyStore.cpp
+++ b/keystore/KeyStore.cpp
@@ -43,10 +43,26 @@
 
 using android::String8;
 
-KeyStore::KeyStore(Entropy* entropy, const sp<Keymaster>& device, const sp<Keymaster>& fallback,
-                   bool allowNewFallback)
-    : mEntropy(entropy), mDevice(device), mFallbackDevice(fallback),
-      mAllowNewFallback(allowNewFallback) {
+sp<Keymaster>& KeymasterDevices::operator[](SecurityLevel secLevel) {
+    static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 &&
+                      uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 &&
+                      uint32_t(SecurityLevel::STRONGBOX) == 2,
+                  "Numeric values of security levels have changed");
+    return at(static_cast<uint32_t>(secLevel));
+}
+
+sp<Keymaster> KeymasterDevices::operator[](SecurityLevel secLevel) const {
+    if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) {
+        LOG(ERROR) << "Invalid security level requested";
+        return nullptr;
+    }
+    return (*const_cast<KeymasterDevices*>(this))[secLevel];
+}
+
+KeyStore::KeyStore(Entropy* entropy, const KeymasterDevices& kmDevices,
+                   SecurityLevel minimalAllowedSecurityLevelForNewKeys)
+    : mEntropy(entropy), mKmDevices(kmDevices),
+      mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE) {
     memset(&mMetaData, '\0', sizeof(mMetaData));
 }
 
@@ -359,7 +375,7 @@
         return rc;
     }
 
-    auto& dev = getDevice(keyBlob);
+    auto dev = getDevice(keyBlob);
 
     if (keyBlob.getType() == ::TYPE_KEY_PAIR || keyBlob.getType() == ::TYPE_KEYMASTER_10) {
         auto ret = KS_HANDLE_HIDL_ERROR(dev->deleteKey(blob2hidlVec(keyBlob)));
@@ -533,8 +549,18 @@
     };
     auto input = blob2hidlVec(key, keyLen);
 
+    SecurityLevel securityLevel = flagsToSecurityLevel(flags);
+    auto kmDevice = getDevice(securityLevel);
+    if (!kmDevice) {
+        // As of this writing the only caller is KeyStore::get in an attempt to import legacy
+        // software keys. It only ever requests TEE as target which must always be present.
+        // If we see this error, we probably have a new and unanticipated caller.
+        ALOGE("No implementation for security level %d. Cannot import key.", securityLevel);
+        return ResponseCode::SYSTEM_ERROR;
+    }
+
     ErrorCode rc = KS_HANDLE_HIDL_ERROR(
-        mDevice->importKey(params.hidl_data(), KeyFormat::PKCS8, input, hidlCb));
+        kmDevice->importKey(params.hidl_data(), KeyFormat::PKCS8, input, hidlCb));
     if (rc != ErrorCode::OK) return ResponseCode::SYSTEM_ERROR;
     if (error != ErrorCode::OK) {
         ALOGE("Keymaster error %d importing key pair", error);
@@ -544,25 +570,26 @@
     Blob keyBlob(&blob[0], blob.size(), NULL, 0, TYPE_KEYMASTER_10);
 
     keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-    keyBlob.setFallback(false);
+    keyBlob.setSecurityLevel(securityLevel);
 
     return put(filename, &keyBlob, userId);
 }
 
 bool KeyStore::isHardwareBacked(const android::String16& keyType) const {
-    if (mDevice == NULL) {
+    // if strongbox device is present TEE must also be present and of sufficiently high version
+    // to support all keys in hardware
+    if (getDevice(SecurityLevel::STRONGBOX)) return true;
+    if (!getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)) {
         ALOGW("can't get keymaster device");
         return false;
     }
 
-    auto version = mDevice->halVersion();
+    auto version = getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)->halVersion();
     if (version.error != ErrorCode::OK) {
         ALOGE("Failed to get HAL version info");
         return false;
     }
 
-    if (!version.isSecure) return false;
-
     if (keyType == kRsaKeyType) return true;  // All versions support RSA
     return keyType == kEcKeyType && version.supportsEc;
 }
diff --git a/keystore/KeyStore.h b/keystore/KeyStore.h
index 463ed8e..cfc5c31 100644
--- a/keystore/KeyStore.h
+++ b/keystore/KeyStore.h
@@ -32,29 +32,42 @@
 
 using ::android::sp;
 
+class KeymasterDevices : public std::array<sp<Keymaster>, 3> {
+  public:
+    sp<Keymaster>& operator[](SecurityLevel secLevel);
+    sp<Keymaster> operator[](SecurityLevel secLevel) const;
+};
+
 class KeyStore {
   public:
-    KeyStore(Entropy* entropy, const sp<Keymaster>& device, const sp<Keymaster>& fallback,
-             bool allowNewFallback);
+    KeyStore(Entropy* entropy, const KeymasterDevices& kmDevices,
+             SecurityLevel minimalAllowedSecurityLevelForNewKeys);
     ~KeyStore();
 
-    sp<Keymaster>& getDevice() { return mDevice; }
+    sp<Keymaster> getDevice(SecurityLevel securityLevel) const { return mKmDevices[securityLevel]; }
 
-    NullOr<sp<Keymaster>&> getFallbackDevice() {
+    std::pair<sp<Keymaster>, SecurityLevel> getMostSecureDevice() const {
+        SecurityLevel level = SecurityLevel::STRONGBOX;
+        do {
+            if (mKmDevices[level].get()) {
+                return {mKmDevices[level], level};
+            }
+            level = static_cast<SecurityLevel>(static_cast<uint32_t>(level) - 1);
+        } while (level != SecurityLevel::SOFTWARE);
+        return {nullptr, SecurityLevel::SOFTWARE};
+    }
+
+    sp<Keymaster> getFallbackDevice() const {
         // we only return the fallback device if the creation of new fallback key blobs is
         // allowed. (also see getDevice below)
         if (mAllowNewFallback) {
-            return mFallbackDevice;
+            return mKmDevices[SecurityLevel::SOFTWARE];
         } else {
-            return {};
+            return nullptr;
         }
     }
 
-    sp<Keymaster>& getDevice(const Blob& blob) {
-        // We return a device, based on the nature of the blob to provide backward
-        // compatibility with old key blobs generated using the fallback device.
-        return blob.isFallback() ? mFallbackDevice : mDevice;
-    }
+    sp<Keymaster> getDevice(const Blob& blob) { return mKmDevices[blob.getSecurityLevel()]; }
 
     ResponseCode initialize();
 
@@ -129,8 +142,7 @@
     static const android::String16 kEcKeyType;
     Entropy* mEntropy;
 
-    sp<Keymaster> mDevice;
-    sp<Keymaster> mFallbackDevice;
+    KeymasterDevices mKmDevices;
     bool mAllowNewFallback;
 
     android::Vector<UserState*> mMasterKeys;
diff --git a/keystore/Keymaster.h b/keystore/Keymaster.h
index cbd4eb6..4712eec 100644
--- a/keystore/Keymaster.h
+++ b/keystore/Keymaster.h
@@ -40,7 +40,7 @@
     struct VersionResult {
         ErrorCode error;
         uint8_t majorVersion;
-        bool isSecure;
+        SecurityLevel securityLevel;
         bool supportsEc;
     };
 
diff --git a/keystore/Keymaster3.cpp b/keystore/Keymaster3.cpp
index c4ddc75..1a17226 100644
--- a/keystore/Keymaster3.cpp
+++ b/keystore/Keymaster3.cpp
@@ -98,7 +98,8 @@
         [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
             bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
             const hidl_string& keymasterAuthorName) {
-            isSecure_ = isSecure;
+            securityLevel_ =
+                isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
             supportsEllipticCurve_ = supportsEllipticCurve;
             supportsSymmetricCryptography_ = supportsSymmetricCryptography;
             supportsAttestation_ = supportsAttestation;
@@ -109,7 +110,7 @@
 
     CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
 
-    if (!isSecure_) {
+    if (securityLevel_ == SecurityLevel::SOFTWARE) {
         majorVersion_ = 3;
     } else if (supportsAttestation_) {
         majorVersion_ = 3;  // Could be 2, doesn't matter.
@@ -122,13 +123,12 @@
 
 Keymaster::VersionResult Keymaster3::halVersion() {
     getVersionIfNeeded();
-    return {ErrorCode::OK, majorVersion_, isSecure_, supportsEllipticCurve_};
+    return {ErrorCode::OK, majorVersion_, securityLevel_, supportsEllipticCurve_};
 }
 
 Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
     getVersionIfNeeded();
-    _hidl_cb(isSecure_ ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
-             keymasterName_ + " (wrapped by keystore::Keymaster3)", authorName_);
+    _hidl_cb(securityLevel_, keymasterName_ + " (wrapped by keystore::Keymaster3)", authorName_);
     return Void();
 }
 
diff --git a/keystore/Keymaster3.h b/keystore/Keymaster3.h
index 172ab23..6d74a12 100644
--- a/keystore/Keymaster3.h
+++ b/keystore/Keymaster3.h
@@ -36,7 +36,8 @@
 
 class Keymaster3 : public Keymaster {
   public:
-    Keymaster3(sp<IKeymaster3Device> km3_dev) : km3_dev_(km3_dev) {}
+    using WrappedIKeymasterDevice = IKeymaster3Device;
+    Keymaster3(sp<IKeymaster3Device> km3_dev) : km3_dev_(km3_dev), haveVersion_(false) {}
 
     VersionResult halVersion() override;
 
@@ -105,9 +106,9 @@
 
     sp<IKeymaster3Device> km3_dev_;
 
-    bool haveVersion_ = false;
+    bool haveVersion_;
     uint8_t majorVersion_;
-    bool isSecure_;
+    SecurityLevel securityLevel_;
     bool supportsEllipticCurve_;
     bool supportsSymmetricCryptography_;
     bool supportsAttestation_;
diff --git a/keystore/Keymaster4.cpp b/keystore/Keymaster4.cpp
new file mode 100644
index 0000000..3edfb53
--- /dev/null
+++ b/keystore/Keymaster4.cpp
@@ -0,0 +1,39 @@
+/*
+**
+** Copyright 2017, 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.
+*/
+#include "Keymaster4.h"
+
+#include <android-base/logging.h>
+
+namespace keystore {
+
+void Keymaster4::getVersionIfNeeded() {
+    if (haveVersion_) return;
+
+    auto rc = dev_->getHardwareInfo([&](SecurityLevel securityLevel, auto...) {
+        securityLevel_ = securityLevel;
+        haveVersion_ = true;
+    });
+
+    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+Keymaster::VersionResult Keymaster4::halVersion() {
+    getVersionIfNeeded();
+    return {ErrorCode::OK, halMajorVersion(), securityLevel_, true};
+}
+
+}  // namespace keystore
diff --git a/keystore/Keymaster4.h b/keystore/Keymaster4.h
index 867f304..53ca08a 100644
--- a/keystore/Keymaster4.h
+++ b/keystore/Keymaster4.h
@@ -30,11 +30,12 @@
 
 class Keymaster4 : public Keymaster {
   public:
-    Keymaster4(sp<IKeymasterDevice> km4_dev) : dev_(km4_dev) {}
+    using WrappedIKeymasterDevice = IKeymaster4Device;
+    Keymaster4(sp<IKeymasterDevice> km4_dev) : haveVersion_(false), dev_(km4_dev) {}
 
     uint8_t halMajorVersion() { return 4; }
 
-    VersionResult halVersion() override { return {ErrorCode::OK, halMajorVersion(), true, true}; }
+    VersionResult halVersion() override;
 
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
         return dev_->getHardwareInfo(_hidl_cb);
@@ -135,6 +136,10 @@
     }
 
   private:
+    void getVersionIfNeeded();
+
+    bool haveVersion_;
+    SecurityLevel securityLevel_;
     sp<IKeymaster4Device> dev_;
 };
 
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index 625d057..aa1ae37 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -327,3 +327,12 @@
 
     return ResponseCode::NO_ERROR;
 }
+
+keystore::SecurityLevel Blob::getSecurityLevel() const {
+    return keystore::flagsToSecurityLevel(mBlob.flags);
+}
+
+void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
+    mBlob.flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
+    mBlob.flags |= keystore::securityLevelToFlags(secLevel);
+}
diff --git a/keystore/blob.h b/keystore/blob.h
index 5335037..665e07a 100644
--- a/keystore/blob.h
+++ b/keystore/blob.h
@@ -22,6 +22,7 @@
 #include <openssl/aes.h>
 #include <openssl/md5.h>
 
+#include <keystore/keymaster_types.h>
 #include <keystore/keystore.h>
 
 constexpr size_t kValueSize = 32768;
@@ -117,6 +118,9 @@
     BlobType getType() const { return BlobType(mBlob.type); }
     void setType(BlobType type) { mBlob.type = uint8_t(type); }
 
+    keystore::SecurityLevel getSecurityLevel() const;
+    void setSecurityLevel(keystore::SecurityLevel);
+
     ResponseCode writeBlob(const std::string& filename, const uint8_t* aes_key, State state,
                            Entropy* entropy);
     ResponseCode readBlob(const std::string& filename, const uint8_t* aes_key, State state);
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index cb64498..07f645f 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -63,6 +63,7 @@
     // encrypted, and it will be stored separately under an unique UID instead. This flag should
     // only be available to system uid.
     KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3,
+    KEYSTORE_FLAG_STRONGBOX = 1 << 4,
 };
 
 #endif
diff --git a/keystore/include/keystore/keystore_client.h b/keystore/include/keystore/keystore_client.h
index 67ebad3..d6a4807 100644
--- a/keystore/include/keystore/keystore_client.h
+++ b/keystore/include/keystore/keystore_client.h
@@ -62,7 +62,7 @@
     // Note: implementations may generate more than one key but they will always
     // have |key_name| as a prefix.
     virtual bool encryptWithAuthentication(const std::string& key_name, const std::string& data,
-                                           std::string* encrypted_data) = 0;
+                                           int32_t flags, std::string* encrypted_data) = 0;
 
     // Decrypts and authenticates |encrypted_data| as output by
     // EncryptWithAuthentication using the key(s) identified by |key_name|. On
@@ -85,8 +85,8 @@
 
     // Adds |entropy| to the random number generator. Returns KM_ERROR_OK on
     // success and a Keystore ResponseCode or keymaster_error_t on failure.
-    virtual KeyStoreNativeReturnCode
-    addRandomNumberGeneratorEntropy(const std::string& entropy) = 0;
+    virtual KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy,
+                                                                     int32_t flags) = 0;
 
     // Generates a key according to the given |key_parameters| and stores it with
     // the given |key_name|. The [hardware|software]_enforced_characteristics of
@@ -95,7 +95,7 @@
     // failure.
     virtual KeyStoreNativeReturnCode
     generateKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters,
-                keystore::AuthorizationSet* hardware_enforced_characteristics,
+                int32_t flags, keystore::AuthorizationSet* hardware_enforced_characteristics,
                 keystore::AuthorizationSet* software_enforced_characteristics) = 0;
 
     // Provides the [hardware|software]_enforced_characteristics of a key
diff --git a/keystore/include/keystore/keystore_client_impl.h b/keystore/include/keystore/keystore_client_impl.h
index a11e2fe..9edd082 100644
--- a/keystore/include/keystore/keystore_client_impl.h
+++ b/keystore/include/keystore/keystore_client_impl.h
@@ -35,7 +35,7 @@
 
     // KeystoreClient methods.
     bool encryptWithAuthentication(const std::string& key_name, const std::string& data,
-                                   std::string* encrypted_data) override;
+                                   int32_t flags, std::string* encrypted_data) override;
     bool decryptWithAuthentication(const std::string& key_name, const std::string& encrypted_data,
                                    std::string* data) override;
     bool oneShotOperation(KeyPurpose purpose, const std::string& key_name,
@@ -43,10 +43,11 @@
                           const std::string& input_data, const std::string& signature_to_verify,
                           keystore::AuthorizationSet* output_parameters,
                           std::string* output_data) override;
-    KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy) override;
+    KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy,
+                                                             int32_t flags) override;
     KeyStoreNativeReturnCode
     generateKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters,
-                keystore::AuthorizationSet* hardware_enforced_characteristics,
+                int32_t flags, keystore::AuthorizationSet* hardware_enforced_characteristics,
                 keystore::AuthorizationSet* software_enforced_characteristics) override;
     KeyStoreNativeReturnCode
     getKeyCharacteristics(const std::string& key_name,
@@ -90,11 +91,11 @@
 
     // Creates an encryption key suitable for EncryptWithAuthentication or
     // verifies attributes if the key already exists. Returns true on success.
-    bool createOrVerifyEncryptionKey(const std::string& key_name);
+    bool createOrVerifyEncryptionKey(const std::string& key_name, int32_t flags);
 
     // Creates an authentication key suitable for EncryptWithAuthentication or
     // verifies attributes if the key already exists. Returns true on success.
-    bool createOrVerifyAuthenticationKey(const std::string& key_name);
+    bool createOrVerifyAuthenticationKey(const std::string& key_name, int32_t flags);
 
     // Verifies attributes of an encryption key suitable for
     // EncryptWithAuthentication. Returns true on success and populates |verified|
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index 137ab48..5f43e56 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -785,10 +785,15 @@
     return Status::ok();
 }
 
-Status KeyStoreService::addRngEntropy(const ::std::vector<uint8_t>& entropy, int32_t* aidl_return) {
-    const auto& device = mKeyStore->getDevice();
-    *aidl_return = static_cast<int32_t>(
-        KeyStoreServiceReturnCode(KS_HANDLE_HIDL_ERROR(device->addRngEntropy(entropy))));
+Status KeyStoreService::addRngEntropy(const ::std::vector<uint8_t>& entropy, int32_t flags,
+                                      int32_t* aidl_return) {
+    auto device = mKeyStore->getDevice(flagsToSecurityLevel(flags));
+    if (!device) {
+        *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+    } else {
+        *aidl_return = static_cast<int32_t>(
+            KeyStoreServiceReturnCode(KS_HANDLE_HIDL_ERROR(device->addRngEntropy(entropy))));
+    }
     return Status::ok();
 }
 
@@ -821,15 +826,18 @@
         }
     }
 
-    bool usingFallback = false;
-    auto& dev = mKeyStore->getDevice();
+    SecurityLevel securityLevel = flagsToSecurityLevel(flags);
+    auto dev = mKeyStore->getDevice(securityLevel);
+    if (!dev) {
+        *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+        return Status::ok();
+    }
     AuthorizationSet keyCharacteristics = params.getParameters();
 
     // TODO: Seed from Linux RNG before this.
-    int32_t result;
-    addRngEntropy(entropy, &result);  // binder error is not possible.
-    if (!KeyStoreServiceReturnCode(result).isOk()) {
-        *aidl_return = static_cast<int32_t>(result);
+    rc = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
+    if (!rc.isOk()) {
+        *aidl_return = static_cast<int32_t>(rc);
         return Status::ok();
     }
 
@@ -849,7 +857,7 @@
         String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
 
         Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
-        keyBlob.setFallback(usingFallback);
+        keyBlob.setSecurityLevel(securityLevel);
         keyBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
         if (isAuthenticationBound(params.getParameters()) &&
             !keyBlob.isCriticalToDeviceEncryption()) {
@@ -867,13 +875,13 @@
     }
     if (!error.isOk()) {
         ALOGE("Failed to generate key -> falling back to software keymaster");
-        usingFallback = true;
+        securityLevel = SecurityLevel::SOFTWARE;
         auto fallback = mKeyStore->getFallbackDevice();
-        if (!fallback.isOk()) {
+        if (!fallback) {
             *aidl_return = static_cast<int32_t>(error);
             return Status::ok();
         }
-        rc = KS_HANDLE_HIDL_ERROR(fallback.value()->generateKey(params.getParameters(), hidl_cb));
+        rc = KS_HANDLE_HIDL_ERROR(fallback->generateKey(params.getParameters(), hidl_cb));
         if (!rc.isOk()) {
             *aidl_return = static_cast<int32_t>(rc);
             return Status::ok();
@@ -897,7 +905,7 @@
     auto kc_buf = kc_stream.str();
     Blob charBlob(reinterpret_cast<const uint8_t*>(kc_buf.data()), kc_buf.size(), NULL, 0,
                   ::TYPE_KEY_CHARACTERISTICS);
-    charBlob.setFallback(usingFallback);
+    charBlob.setSecurityLevel(securityLevel);
     charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
 
     *aidl_return =
@@ -956,7 +964,7 @@
     }
 
     auto hidlKeyBlob = blob2hidlVec(keyBlob);
-    auto& dev = mKeyStore->getDevice(keyBlob);
+    auto dev = mKeyStore->getDevice(keyBlob);
 
     KeyStoreServiceReturnCode error;
 
@@ -1024,8 +1032,12 @@
         return Status::ok();
     }
 
-    bool usingFallback = false;
-    auto& dev = mKeyStore->getDevice();
+    SecurityLevel securityLevel = flagsToSecurityLevel(flags);
+    auto dev = mKeyStore->getDevice(securityLevel);
+    if (!dev) {
+        *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+        return Status::ok();
+    }
 
     String8 name8(name);
 
@@ -1045,7 +1057,7 @@
         String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
 
         Blob ksBlob(&keyBlob[0], keyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
-        ksBlob.setFallback(usingFallback);
+        ksBlob.setSecurityLevel(securityLevel);
         ksBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
         if (isAuthenticationBound(params.getParameters()) &&
             !ksBlob.isCriticalToDeviceEncryption()) {
@@ -1066,14 +1078,14 @@
     // now check error from callback
     if (!error.isOk()) {
         ALOGE("Failed to import key -> falling back to software keymaster");
-        usingFallback = true;
+        securityLevel = SecurityLevel::SOFTWARE;
         auto fallback = mKeyStore->getFallbackDevice();
-        if (!fallback.isOk()) {
+        if (!fallback) {
             *aidl_return = static_cast<int32_t>(error);
             return Status::ok();
         }
-        rc = KS_HANDLE_HIDL_ERROR(fallback.value()->importKey(params.getParameters(),
-                                                              KeyFormat(format), keyData, hidlCb));
+        rc = KS_HANDLE_HIDL_ERROR(
+            fallback->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb));
         // possible hidl error
         if (!rc.isOk()) {
             *aidl_return = static_cast<int32_t>(rc);
@@ -1100,7 +1112,7 @@
 
     Blob charBlob(reinterpret_cast<const uint8_t*>(kcBuf.data()), kcBuf.size(), NULL, 0,
                   ::TYPE_KEY_CHARACTERISTICS);
-    charBlob.setFallback(usingFallback);
+    charBlob.setSecurityLevel(securityLevel);
     charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
 
     *aidl_return =
@@ -1131,7 +1143,7 @@
     }
 
     auto key = blob2hidlVec(keyBlob);
-    auto& dev = mKeyStore->getDevice(keyBlob);
+    auto dev = mKeyStore->getDevice(keyBlob);
 
     auto hidlCb = [&](ErrorCode ret, const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
         result->resultCode = ret;
@@ -1204,7 +1216,7 @@
     if (!result->resultCode.isOk()) return Status::ok();
 
     auto key = blob2hidlVec(keyBlob);
-    auto& dev = mKeyStore->getDevice(keyBlob);
+    auto dev = mKeyStore->getDevice(keyBlob);
     AuthorizationSet opParams = params.getParameters();
     KeyCharacteristics characteristics;
     result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics);
@@ -1259,9 +1271,7 @@
 
     // Add entropy to the device first.
     if (entropy.size()) {
-        int32_t resultCode;
-        addRngEntropy(entropy, &resultCode);  // binder error is not possible
-        result->resultCode = KeyStoreServiceReturnCode(resultCode);
+        result->resultCode = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
         if (!result->resultCode.isOk()) {
             return Status::ok();
         }
@@ -1418,9 +1428,7 @@
     if (!result->resultCode.isOk()) return Status::ok();
 
     if (entropy.size()) {
-        int resultCode;
-        addRngEntropy(entropy, &resultCode);  // binder error is not possible
-        result->resultCode = KeyStoreServiceReturnCode(resultCode);
+        result->resultCode = KS_HANDLE_HIDL_ERROR(op.device->addRngEntropy(entropy));
         if (!result->resultCode.isOk()) {
             return Status::ok();
         }
@@ -1574,7 +1582,7 @@
     };
 
     auto hidlKey = blob2hidlVec(keyBlob);
-    auto& dev = mKeyStore->getDevice(keyBlob);
+    auto dev = mKeyStore->getDevice(keyBlob);
     rc = KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb));
     if (!rc.isOk()) {
         *aidl_return = static_cast<int32_t>(rc);
@@ -1624,7 +1632,15 @@
     }
 
     // Generate temporary key.
-    auto& dev = mKeyStore->getDevice();
+    sp<Keymaster> dev;
+    SecurityLevel securityLevel;
+    std::tie(dev, securityLevel) = mKeyStore->getMostSecureDevice();
+
+    if (securityLevel == SecurityLevel::SOFTWARE) {
+        *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
+        return Status::ok();
+    }
+
     KeyStoreServiceReturnCode error;
     ::std::vector<uint8_t> hidlKey;
 
@@ -2048,7 +2064,7 @@
     ALOGI("upgradeKeyBlob %s %d", name8.string(), uid);
 
     auto hidlKey = blob2hidlVec(*blob);
-    auto& dev = mKeyStore->getDevice(*blob);
+    auto dev = mKeyStore->getDevice(*blob);
 
     KeyStoreServiceReturnCode error;
     auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& upgradedKeyBlob) {
@@ -2070,7 +2086,7 @@
 
         Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
                      0 /* infoLength */, ::TYPE_KEYMASTER_10);
-        newBlob.setFallback(blob->isFallback());
+        newBlob.setSecurityLevel(blob->getSecurityLevel());
         newBlob.setEncrypted(blob->isEncrypted());
         newBlob.setSuperEncrypted(blob->isSuperEncrypted());
         newBlob.setCriticalToDeviceEncryption(blob->isCriticalToDeviceEncryption());
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index da3e60a..16d7397 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -100,7 +100,7 @@
     ::android::binder::Status is_hardware_backed(const ::android::String16& string,
                                                  int32_t* _aidl_return) override;
     ::android::binder::Status clear_uid(int64_t uid, int32_t* _aidl_return) override;
-    ::android::binder::Status addRngEntropy(const ::std::vector<uint8_t>& data,
+    ::android::binder::Status addRngEntropy(const ::std::vector<uint8_t>& data, int32_t flags,
                                             int32_t* _aidl_return) override;
     ::android::binder::Status
     generateKey(const ::android::String16& alias,
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index 9e184e8..6e995e0 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -39,8 +39,8 @@
     printf("Usage: keystore_client_v2 <command> [options]\n");
     printf("Commands: brillo-platform-test [--prefix=<test_name_prefix>] [--test_for_0_3]\n"
            "          list-brillo-tests\n"
-           "          add-entropy --input=<entropy>\n"
-           "          generate --name=<key_name>\n"
+           "          add-entropy --input=<entropy> [--seclevel=software|strongbox|tee(default)]\n"
+           "          generate --name=<key_name> [--seclevel=software|strongbox|tee(default)]\n"
            "          get-chars --name=<key_name>\n"
            "          export --name=<key_name>\n"
            "          delete --name=<key_name>\n"
@@ -48,7 +48,8 @@
            "          exists --name=<key_name>\n"
            "          list [--prefix=<key_name_prefix>]\n"
            "          sign-verify --name=<key_name>\n"
-           "          [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n");
+           "          [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n"
+           "                       [--seclevel=software|strongbox|tee(default)]\n");
     exit(1);
 }
 
@@ -76,8 +77,9 @@
     std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
     AuthorizationSet hardware_enforced_characteristics;
     AuthorizationSet software_enforced_characteristics;
-    auto result = keystore->generateKey("tmp", parameters, &hardware_enforced_characteristics,
-                                        &software_enforced_characteristics);
+    auto result =
+        keystore->generateKey("tmp", parameters, 0 /*flags*/, &hardware_enforced_characteristics,
+                              &software_enforced_characteristics);
     const char kBoldRedAbort[] = "\033[1;31mABORT\033[0m";
     if (!result.isOk()) {
         LOG(ERROR) << "Failed to generate key: " << result;
@@ -254,14 +256,14 @@
     }
 }
 
-int AddEntropy(const std::string& input) {
+int AddEntropy(const std::string& input, int32_t flags) {
     std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
-    int32_t result = keystore->addRandomNumberGeneratorEntropy(input);
+    int32_t result = keystore->addRandomNumberGeneratorEntropy(input, flags);
     printf("AddEntropy: %d\n", result);
     return result;
 }
 
-int GenerateKey(const std::string& name) {
+int GenerateKey(const std::string& name, int32_t flags) {
     std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
     AuthorizationSetBuilder params;
     params.RsaSigningKey(2048, 65537)
@@ -274,7 +276,7 @@
         .Authorization(TAG_NO_AUTH_REQUIRED);
     AuthorizationSet hardware_enforced_characteristics;
     AuthorizationSet software_enforced_characteristics;
-    auto result = keystore->generateKey(name, params, &hardware_enforced_characteristics,
+    auto result = keystore->generateKey(name, params, flags, &hardware_enforced_characteristics,
                                         &software_enforced_characteristics);
     printf("GenerateKey: %d\n", int32_t(result));
     if (result.isOk()) {
@@ -399,11 +401,11 @@
 }
 
 int Encrypt(const std::string& key_name, const std::string& input_filename,
-            const std::string& output_filename) {
+            const std::string& output_filename, int32_t flags) {
     std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
     std::string input = ReadFile(input_filename);
     std::string output;
-    if (!keystore->encryptWithAuthentication(key_name, input, &output)) {
+    if (!keystore->encryptWithAuthentication(key_name, input, flags, &output)) {
         printf("EncryptWithAuthentication failed.\n");
         return 1;
     }
@@ -424,6 +426,18 @@
     return 0;
 }
 
+uint32_t securityLevelOption2Flags(const CommandLine& cmd) {
+    if (cmd.HasSwitch("seclevel")) {
+        auto str = cmd.GetSwitchValueASCII("seclevel");
+        if (str == "strongbox") {
+            return KEYSTORE_FLAG_STRONGBOX;
+        } else if (str == "software") {
+            return KEYSTORE_FLAG_FALLBACK;
+        }
+    }
+    return KEYSTORE_FLAG_NONE;
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -439,9 +453,11 @@
     } else if (args[0] == "list-brillo-tests") {
         return ListTestCases();
     } else if (args[0] == "add-entropy") {
-        return AddEntropy(command_line->GetSwitchValueASCII("input"));
+        return AddEntropy(command_line->GetSwitchValueASCII("input"),
+                          securityLevelOption2Flags(*command_line));
     } else if (args[0] == "generate") {
-        return GenerateKey(command_line->GetSwitchValueASCII("name"));
+        return GenerateKey(command_line->GetSwitchValueASCII("name"),
+                           securityLevelOption2Flags(*command_line));
     } else if (args[0] == "get-chars") {
         return GetCharacteristics(command_line->GetSwitchValueASCII("name"));
     } else if (args[0] == "export") {
@@ -457,9 +473,9 @@
     } else if (args[0] == "sign-verify") {
         return SignAndVerify(command_line->GetSwitchValueASCII("name"));
     } else if (args[0] == "encrypt") {
-        return Encrypt(command_line->GetSwitchValueASCII("name"),
-                       command_line->GetSwitchValueASCII("in"),
-                       command_line->GetSwitchValueASCII("out"));
+        return Encrypt(
+            command_line->GetSwitchValueASCII("name"), command_line->GetSwitchValueASCII("in"),
+            command_line->GetSwitchValueASCII("out"), securityLevelOption2Flags(*command_line));
     } else if (args[0] == "decrypt") {
         return Decrypt(command_line->GetSwitchValueASCII("name"),
                        command_line->GetSwitchValueASCII("in"),
diff --git a/keystore/keystore_client_impl.cpp b/keystore/keystore_client_impl.cpp
index 4ff865a..6d998ad 100644
--- a/keystore/keystore_client_impl.cpp
+++ b/keystore/keystore_client_impl.cpp
@@ -61,18 +61,18 @@
 }
 
 bool KeystoreClientImpl::encryptWithAuthentication(const std::string& key_name,
-                                                   const std::string& data,
+                                                   const std::string& data, int32_t flags,
                                                    std::string* encrypted_data) {
     // The encryption algorithm is AES-256-CBC with PKCS #7 padding and a random
     // IV. The authentication algorithm is HMAC-SHA256 and is computed over the
     // cipher-text (i.e. Encrypt-then-MAC approach). This was chosen over AES-GCM
     // because hardware support for GCM is not mandatory for all Brillo devices.
     std::string encryption_key_name = key_name + kEncryptSuffix;
-    if (!createOrVerifyEncryptionKey(encryption_key_name)) {
+    if (!createOrVerifyEncryptionKey(encryption_key_name, flags)) {
         return false;
     }
     std::string authentication_key_name = key_name + kAuthenticateSuffix;
-    if (!createOrVerifyAuthenticationKey(authentication_key_name)) {
+    if (!createOrVerifyAuthenticationKey(authentication_key_name, flags)) {
         return false;
     }
     AuthorizationSetBuilder encrypt_params;
@@ -179,24 +179,23 @@
 }
 
 KeyStoreNativeReturnCode
-KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy) {
+KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy, int32_t flags) {
     int32_t result;
-    auto binder_result = keystore_->addRngEntropy(blob2hidlVec(entropy), &result);
+    auto binder_result = keystore_->addRngEntropy(blob2hidlVec(entropy), flags, &result);
     if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
     return KeyStoreNativeReturnCode(result);
 }
 
 KeyStoreNativeReturnCode
 KeystoreClientImpl::generateKey(const std::string& key_name, const AuthorizationSet& key_parameters,
-                                AuthorizationSet* hardware_enforced_characteristics,
+                                int32_t flags, AuthorizationSet* hardware_enforced_characteristics,
                                 AuthorizationSet* software_enforced_characteristics) {
     String16 key_name16(key_name.data(), key_name.size());
     ::android::security::keymaster::KeyCharacteristics characteristics;
     int32_t result;
     auto binder_result = keystore_->generateKey(
         key_name16, ::android::security::keymaster::KeymasterArguments(key_parameters.hidl_data()),
-        hidl_vec<uint8_t>() /* entropy */, kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics,
-        &result);
+        hidl_vec<uint8_t>() /* entropy */, kDefaultUID, flags, &characteristics, &result);
     if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
 
     /* assignment (hidl_vec<KeyParameter> -> AuthorizationSet) makes a deep copy.
@@ -388,7 +387,7 @@
     return next_virtual_handle_++;
 }
 
-bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name) {
+bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name, int32_t flags) {
     bool key_exists = doesKeyExist(key_name);
     if (key_exists) {
         bool verified = false;
@@ -412,8 +411,9 @@
             .Authorization(TAG_NO_AUTH_REQUIRED);
         AuthorizationSet hardware_enforced_characteristics;
         AuthorizationSet software_enforced_characteristics;
-        auto result = generateKey(key_name, key_parameters, &hardware_enforced_characteristics,
-                                  &software_enforced_characteristics);
+        auto result =
+            generateKey(key_name, key_parameters, flags, &hardware_enforced_characteristics,
+                        &software_enforced_characteristics);
         if (!result.isOk()) {
             ALOGE("Failed to generate encryption key: %d", int32_t(result));
             return false;
@@ -425,7 +425,8 @@
     return true;
 }
 
-bool KeystoreClientImpl::createOrVerifyAuthenticationKey(const std::string& key_name) {
+bool KeystoreClientImpl::createOrVerifyAuthenticationKey(const std::string& key_name,
+                                                         int32_t flags) {
     bool key_exists = doesKeyExist(key_name);
     if (key_exists) {
         bool verified = false;
@@ -449,8 +450,9 @@
             .Authorization(TAG_NO_AUTH_REQUIRED);
         AuthorizationSet hardware_enforced_characteristics;
         AuthorizationSet software_enforced_characteristics;
-        auto result = generateKey(key_name, key_parameters, &hardware_enforced_characteristics,
-                                  &software_enforced_characteristics);
+        auto result =
+            generateKey(key_name, key_parameters, flags, &hardware_enforced_characteristics,
+                        &software_enforced_characteristics);
         if (!result.isOk()) {
             ALOGE("Failed to generate authentication key: %d", int32_t(result));
             return false;
diff --git a/keystore/keystore_main.cpp b/keystore/keystore_main.cpp
index 56fe0d5..8a00a8d 100644
--- a/keystore/keystore_main.cpp
+++ b/keystore/keystore_main.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "keystore"
+
 #include <android-base/logging.h>
+#include <android/hidl/manager/1.1/IServiceManager.h>
 #include <android/security/IKeystoreService.h>
 #include <android/system/wifi/keystore/1.0/IKeystore.h>
 #include <binder/IPCThreadState.h>
@@ -28,6 +31,7 @@
 
 #include "KeyStore.h"
 #include "Keymaster3.h"
+#include "Keymaster4.h"
 #include "entropy.h"
 #include "key_store_service.h"
 #include "legacy_keymaster_device_wrapper.h"
@@ -43,12 +47,89 @@
 using ::android::hardware::configureRpcThreadpool;
 using ::android::system::wifi::keystore::V1_0::IKeystore;
 using ::android::system::wifi::keystore::V1_0::implementation::Keystore;
+using ::android::hidl::manager::V1_1::IServiceManager;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::keymaster::V4_0::SecurityLevel;
 
 using keystore::Keymaster;
+using keystore::Keymaster3;
+using keystore::Keymaster4;
 
-/**
- * TODO implement keystore daemon using binderized keymaster HAL.
- */
+using keystore::KeymasterDevices;
+
+template <typename Wrapper>
+KeymasterDevices enumerateKeymasterDevices(IServiceManager* serviceManager) {
+    KeymasterDevices result;
+    serviceManager->listByInterface(
+        Wrapper::WrappedIKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
+            auto try_get_device = [&](const auto& name, bool fail_silent) {
+                auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
+                if (fail_silent && !device) return;
+                CHECK(device) << "Failed to get service for \""
+                              << Wrapper::WrappedIKeymasterDevice::descriptor
+                              << "\" with interface name \"" << name << "\"";
+
+                sp<Keymaster> kmDevice(new Wrapper(device));
+                auto halVersion = kmDevice->halVersion();
+                SecurityLevel securityLevel = halVersion.securityLevel;
+                LOG(INFO) << "found " << Wrapper::WrappedIKeymasterDevice::descriptor
+                          << " with interface name " << name << " and seclevel "
+                          << toString(securityLevel);
+                CHECK(static_cast<uint32_t>(securityLevel) < result.size())
+                    << "Security level of \"" << Wrapper::WrappedIKeymasterDevice::descriptor
+                    << "\" with interface name \"" << name << "\" out of range";
+                auto& deviceSlot = result[securityLevel];
+                if (deviceSlot) {
+                    if (!fail_silent) {
+                        LOG(WARNING) << "Implementation of \""
+                                     << Wrapper::WrappedIKeymasterDevice::descriptor
+                                     << "\" with interface name \"" << name
+                                     << "\" and security level: " << toString(securityLevel)
+                                     << " Masked by other implementation of Keymaster";
+                    }
+                } else {
+                    deviceSlot = kmDevice;
+                }
+            };
+            bool has_default = false;
+            for (auto& n : names) {
+                try_get_device(n, false);
+                if (n == "default") has_default = true;
+            }
+            // Make sure that we always check the default device. If we enumerate only what is
+            // known to hwservicemanager, we miss a possible passthrough HAL.
+            if (!has_default) {
+                try_get_device("default", true /* fail_silent */);
+            }
+        });
+    return result;
+}
+
+KeymasterDevices initializeKeymasters() {
+    auto serviceManager = android::hidl::manager::V1_1::IServiceManager::getService();
+    CHECK(serviceManager.get()) << "Failed to get ServiceManager";
+    auto result = enumerateKeymasterDevices<Keymaster4>(serviceManager.get());
+    CHECK(result[SecurityLevel::TRUSTED_ENVIRONMENT] || !result[SecurityLevel::STRONGBOX])
+        << "We cannot have a Strongbox keymaster implementation without a TEE implementation";
+    auto softKeymaster = result[SecurityLevel::SOFTWARE];
+    if (!result[SecurityLevel::TRUSTED_ENVIRONMENT]) {
+        result = enumerateKeymasterDevices<Keymaster3>(serviceManager.get());
+    }
+    if (softKeymaster) result[SecurityLevel::SOFTWARE] = softKeymaster;
+    if (result[SecurityLevel::SOFTWARE] && !result[SecurityLevel::TRUSTED_ENVIRONMENT]) {
+        LOG(WARNING) << "No secure Keymaster implementation found, but device offers insecure"
+                        " Keymaster HAL. Using as default.";
+        result[SecurityLevel::TRUSTED_ENVIRONMENT] = result[SecurityLevel::SOFTWARE];
+        result[SecurityLevel::SOFTWARE] = nullptr;
+    }
+    if (!result[SecurityLevel::SOFTWARE]) {
+        auto fbdev = android::keystore::makeSoftwareKeymasterDevice();
+        CHECK(fbdev.get()) << "Unable to create Software Keymaster Device";
+        result[SecurityLevel::SOFTWARE] = new keystore::Keymaster3(fbdev);
+    }
+    return result;
+}
 
 int main(int argc, char* argv[]) {
     using android::hardware::hidl_string;
@@ -58,26 +139,25 @@
     Entropy entropy;
     CHECK(entropy.open()) << "Failed to open entropy source.";
 
-    auto hwdev = android::hardware::keymaster::V3_0::IKeymasterDevice::getService();
-    CHECK(hwdev.get()) << "Failed to load @3.0::IKeymasterDevice";
-    sp<Keymaster> dev = new keystore::Keymaster3(hwdev);
+    auto kmDevices = initializeKeymasters();
 
-    auto fbdev = android::keystore::makeSoftwareKeymasterDevice();
-    if (fbdev.get() == nullptr) return -1;
-    sp<Keymaster> fallback = new keystore::Keymaster3(fbdev);
+    CHECK(kmDevices[SecurityLevel::SOFTWARE]) << "Missing software Keymaster device";
+    CHECK(kmDevices[SecurityLevel::TRUSTED_ENVIRONMENT])
+        << "Error no viable keymaster device found";
 
     CHECK(configure_selinux() != -1) << "Failed to configure SELinux.";
 
-    auto halVersion = dev->halVersion();
+    auto halVersion = kmDevices[SecurityLevel::TRUSTED_ENVIRONMENT]->halVersion();
     CHECK(halVersion.error == keystore::ErrorCode::OK)
         << "Error " << toString(halVersion.error) << " getting HAL version";
 
     // If the hardware is keymaster 2.0 or higher we will not allow the fallback device for import
     // or generation of keys. The fallback device is only used for legacy keys present on the
     // device.
-    bool allowNewFallbackDevice = halVersion.majorVersion >= 2 && halVersion.isSecure;
+    SecurityLevel minimalAllowedSecurityLevelForNewKeys =
+        halVersion.majorVersion >= 2 ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
 
-    keystore::KeyStore keyStore(&entropy, dev, fallback, allowNewFallbackDevice);
+    keystore::KeyStore keyStore(&entropy, kmDevices, minimalAllowedSecurityLevelForNewKeys);
     keyStore.initialize();
     android::sp<android::IServiceManager> sm = android::defaultServiceManager();
     android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(&keyStore);
diff --git a/keystore/keystore_utils.cpp b/keystore/keystore_utils.cpp
index 543a137..3da3791 100644
--- a/keystore/keystore_utils.cpp
+++ b/keystore/keystore_utils.cpp
@@ -28,6 +28,8 @@
 #include <keystore/keymaster_types.h>
 #include <keystore/keystore_client.h>
 
+#include "blob.h"
+
 size_t readFully(int fd, uint8_t* data, size_t size) {
     size_t remaining = size;
     while (remaining > 0) {
@@ -92,3 +94,37 @@
 uid_t get_user_id(uid_t uid) {
     return uid / AID_USER;
 }
+
+namespace keystore {
+
+hidl_vec<uint8_t> blob2hidlVec(const Blob& blob) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(blob.getValue()), blob.getLength());
+    return result;
+}
+
+SecurityLevel flagsToSecurityLevel(int32_t flags) {
+    switch (flags & (KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX)) {
+    case KEYSTORE_FLAG_FALLBACK:
+    // treating Strongbox flag as "don't care" if Fallback is set
+    case (KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX):
+        return SecurityLevel::SOFTWARE;
+    case KEYSTORE_FLAG_STRONGBOX:
+        return SecurityLevel::STRONGBOX;
+    default:
+        return SecurityLevel::TRUSTED_ENVIRONMENT;
+    }
+}
+
+uint32_t securityLevelToFlags(SecurityLevel secLevel) {
+    switch (secLevel) {
+    case SecurityLevel::SOFTWARE:
+        return KEYSTORE_FLAG_FALLBACK;
+    case SecurityLevel::STRONGBOX:
+        return KEYSTORE_FLAG_STRONGBOX;
+    default:
+        return 0;
+    }
+}
+
+}  // namespace keystore
diff --git a/keystore/keystore_utils.h b/keystore/keystore_utils.h
index 7757f56..f1211de 100644
--- a/keystore/keystore_utils.h
+++ b/keystore/keystore_utils.h
@@ -27,8 +27,6 @@
 
 #include <keystore/keymaster_types.h>
 
-#include "blob.h"
-
 size_t readFully(int fd, uint8_t* data, size_t size);
 size_t writeFully(int fd, uint8_t* data, size_t size);
 
@@ -56,13 +54,14 @@
 };
 typedef std::unique_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
 
+class Blob;
+
 namespace keystore {
 
-inline static hidl_vec<uint8_t> blob2hidlVec(const Blob& blob) {
-    hidl_vec<uint8_t> result;
-    result.setToExternal(const_cast<uint8_t*>(blob.getValue()), blob.getLength());
-    return result;
-}
+hidl_vec<uint8_t> blob2hidlVec(const Blob& blob);
+
+SecurityLevel flagsToSecurityLevel(int32_t flags);
+uint32_t securityLevelToFlags(SecurityLevel secLevel);
 
 }  // namespace keystore