Reintroduce KM0 decryption support

On Android 7 and earlier on FP2, the legacy API version 0.3 Qualcomm
keymaster is used to encrypt the data partition (FDE). Reintroduce
support for legacy keymasters, to be able to decrypt userdata after a
Android 7-to-9 upgrade.

Issue: FP2P-383
Issue: FP2P-506
Change-Id: I057dce6aaef37ebcd7769447a57455c9dd650234
diff --git a/Android.bp b/Android.bp
index fe0b8e7..2bb0972 100644
--- a/Android.bp
+++ b/Android.bp
@@ -236,6 +236,7 @@
         "legacy_support/keymaster_passthrough_key.cpp",
         "legacy_support/keymaster_passthrough_engine.cpp",
         "legacy_support/keymaster_passthrough_operation.cpp",
+        "contexts/keymaster0_passthrough_context.cpp",
         "contexts/keymaster1_passthrough_context.cpp",
         "contexts/keymaster2_passthrough_context.cpp",
         "ng/AndroidKeymaster3Device.cpp",
diff --git a/contexts/keymaster0_passthrough_context.cpp b/contexts/keymaster0_passthrough_context.cpp
new file mode 100644
index 0000000..4b06c0d
--- /dev/null
+++ b/contexts/keymaster0_passthrough_context.cpp
@@ -0,0 +1,84 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+** Copyright 2020, Fairphone B.V.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "KM0_passthrough"
+#include <keymaster/contexts/keymaster0_passthrough_context.h>
+
+#include <memory>
+
+#include <log/log.h>
+
+
+namespace keymaster {
+
+Keymaster0PassthroughContext::Keymaster0PassthroughContext(keymaster0_device_t *dev)
+    : PureSoftKeymasterContext() {
+    km0_engine_.reset(new Keymaster0Engine(dev));
+    // This discards the parent, software-only RSA and EC factories.
+    rsa_factory_.reset(new RsaKeymaster0KeyFactory(this, km0_engine_.get()));
+    ec_factory_.reset(new EcdsaKeymaster0KeyFactory(this, km0_engine_.get()));
+}
+
+Keymaster0PassthroughContext::~Keymaster0PassthroughContext() {
+}
+
+keymaster_error_t Keymaster0PassthroughContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                                         const AuthorizationSet& additional_params,
+                                                         UniquePtr<Key>* key) const {
+    // Try software first, where we can be sure it behaves as expected if it
+    // cannot parse the blob.
+    keymaster_error_t error = PureSoftKeymasterContext::ParseKeyBlob(blob, additional_params, key);
+    if (error == KM_ERROR_OK) {
+        ALOGD("Software keymaster successfully parsed the key blob.");
+        return error;
+    }
+    ALOGD("Software keymaster cannot parse the blob; trying legacy hardware keymaster.");
+
+    // KM0 doesn't provide an interface to get key characteristics. Instead, we
+    // have to make assumptions here and check for failures reported by the
+    // hardware engine.
+
+    // Declare that all operations shall be handled by the hardware keymaster.
+    AuthorizationSet hw_enforced;
+    hw_enforced.push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    hw_enforced.push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+    hw_enforced.push_back(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+    hw_enforced.push_back(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+    hw_enforced.push_back(TAG_ALL_USERS);
+    hw_enforced.push_back(TAG_NO_AUTH_REQUIRED);
+    // The FP2/msm8974 legacy Android 6 Qualcomm keymaster supports RSA only, no
+    // digest, no padding.
+    hw_enforced.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+    hw_enforced.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    hw_enforced.push_back(TAG_PADDING, KM_PAD_NONE);
+    AuthorizationSet sw_enforced;
+
+    // The factory takes ownership of the object, so we need a copy.
+    auto key_material = blob;
+    error = rsa_factory_->LoadKey(move(key_material), additional_params, move(hw_enforced),
+                                  move(sw_enforced), key);
+
+    if (error == KM_ERROR_OK) {
+        ALOGI("Legacy hardware keymaster reports success while parsing the key blob.");
+    } else {
+        ALOGI("Legacy hardware keymaster reports failure while parsing the key blob: %i", error);
+    }
+    return error;
+}
+
+}
diff --git a/include/keymaster/contexts/keymaster0_passthrough_context.h b/include/keymaster/contexts/keymaster0_passthrough_context.h
index 395c757..5bd704d 100644
--- a/include/keymaster/contexts/keymaster0_passthrough_context.h
+++ b/include/keymaster/contexts/keymaster0_passthrough_context.h
@@ -1,6 +1,7 @@
 /*
 **
 ** Copyright 2017, The Android Open Source Project
+** Copyright 2020, Fairphone B.V.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -30,11 +31,11 @@
 
 class Keymaster0PassthroughContext : public PureSoftKeymasterContext {
 public:
-    Keymaster0PassthroughContext(keymaster0_device_t *dev) : PureSoftKeymasterContext() {
-        km0_engine_.reset(new Keymaster0Engine(dev));
-        rsa_factory_.reset(new RsaKeymaster0KeyFactory(this, km0_engine_.get()));
-        ec_factory_.reset(new EcdsaKeymaster0KeyFactory(this, km0_engine_.get()));
-    }
+    Keymaster0PassthroughContext(keymaster0_device_t *dev);
+    ~Keymaster0PassthroughContext() override;
+    keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                   const AuthorizationSet& additional_params,
+                                   UniquePtr<Key>* key) const override;
 
 private:
     UniquePtr<Keymaster0Engine> km0_engine_;