Provide alternate SE RoT provisioning path.

On some devices it is infeasible to provision the KeyMint RoT bits in
the Android Bootloader.  This provides an alternate path to provision
them from the TEE during early boot.

Bug: 219076736
Test: VtsAidlKeyMintTargetTest
Change-Id: If69f7e25e58edbf4d2190084e2c0a03a94bfa5d6
Merged-In: If69f7e25e58edbf4d2190084e2c0a03a94bfa5d6
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index fa643fc..dcc22c4 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -49,5 +49,8 @@
   void earlyBootEnded();
   byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
   android.hardware.security.keymint.KeyCharacteristics[] getKeyCharacteristics(in byte[] keyBlob, in byte[] appId, in byte[] appData);
+  byte[16] getRootOfTrustChallenge();
+  byte[] getRootOfTrust(in byte[16] challenge);
+  void sendRootOfTrust(in byte[] rootOfTrust);
   const int AUTH_TOKEN_MAC_LENGTH = 32;
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 4b63799..da02d54 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -851,4 +851,82 @@
      */
     KeyCharacteristics[] getKeyCharacteristics(
             in byte[] keyBlob, in byte[] appId, in byte[] appData);
+
+    /**
+     * Returns a 16-byte random challenge nonce, used to prove freshness when exchanging root of
+     * trust data.
+     *
+     * This method may only be implemented by StrongBox KeyMint.  TEE KeyMint implementations must
+     * return ErrorCode::UNIMPLEMENTED.  StrongBox KeyMint implementations MAY return UNIMPLEMENTED,
+     * to indicate that they have an alternative mechanism for getting the data.  If the StrongBox
+     * implementation returns UNIMPLEMENTED, the client should not call `getRootofTrust()` or
+     * `sendRootOfTrust()`.
+     */
+    byte[16] getRootOfTrustChallenge();
+
+    /**
+     * Returns the TEE KeyMint Root of Trust data.
+     *
+     * This method is required for TEE KeyMint.  StrongBox KeyMint implementations MUST return
+     * ErrorCode::UNIMPLEMENTED.
+     *
+     * The returned data is an encoded COSE_Mac0 structure, denoted MacedRootOfTrust in the
+     * following CDDL schema.  Note that K_mac is the shared HMAC key used for auth tokens, etc.:
+     *
+     *     MacedRootOfTrust = [               ; COSE_Mac0 (untagged)
+     *         protected: bstr .cbor {
+     *             1 : 5,                     ; Algorithm : HMAC-256
+     *         },
+     *         unprotected : {},
+     *         payload : bstr .cbor RootOfTrust,
+     *         tag : bstr HMAC-256(K_mac, MAC_structure)
+     *     ]
+     *
+     *     MAC_structure = [
+     *         context : "MAC0",
+     *         protected : bstr .cbor {
+     *             1 : 5,                     ; Algorithm : HMAC-256
+     *         },
+     *         external_aad : bstr .size 16   ; Value of challenge argument
+     *         payload : bstr .cbor RootOfTrust,
+     *     ]
+     *
+     *     RootOfTrust = [
+     *         verifiedBootKey : bstr .size 32,
+     *         deviceLocked : bool,
+     *         verifiedBootState : &VerifiedBootState,
+     *         verifiedBootHash : bstr .size 32,
+     *         bootPatchLevel : int,          ; See Tag::BOOT_PATCHLEVEL
+     *     ]
+     *
+     *     VerifiedBootState = (
+     *         Verified : 0,
+     *         SelfSigned : 1,
+     *         Unverified : 2,
+     *         Failed : 3
+     *     )
+     */
+    byte[] getRootOfTrust(in byte[16] challenge);
+
+    /**
+     * Delivers the TEE KeyMint Root of Trust data to StrongBox KeyMint.  See `getRootOfTrust()`
+     * above for specification of the data format and cryptographic security structure.
+     *
+     * The implementation must verify the MAC on the RootOfTrust data.  If it is valid, and if this
+     * is the first time since reboot that StrongBox KeyMint has received this data, it must store
+     * the RoT data for use in key attestation requests, then return ErrorCode::ERROR_OK.
+     *
+     * If the MAC on the Root of Trust data and challenge is incorrect, the implementation must
+     * return ErrorCode::VERIFICATION_FAILED.
+     *
+     * If the RootOfTrust data has already been received since the last boot, the implementation
+     * must validate the data and return ErrorCode::VERIFICATION_FAILED or ErrorCode::ERROR_OK
+     * according to the result, but must not store the data for use in key attestation requests,
+     * even if verification succeeds.  On success, the challenge is invalidated and a new challenge
+     * must be requested before the RootOfTrust data may be sent again.
+     *
+     * This method is optional for StrongBox KeyMint, which MUST return ErrorCode::UNIMPLEMENTED if
+     * not implemented.  TEE KeyMint implementations must return ErrorCode::UNIMPLEMENTED.
+     */
+    void sendRootOfTrust(in byte[] rootOfTrust);
 }
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 91db3c8..1616e65 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -54,6 +54,7 @@
         "AttestKeyTest.cpp",
         "DeviceUniqueAttestationTest.cpp",
         "KeyMintTest.cpp",
+        "SecureElementProvisioningTest.cpp",
     ],
     static_libs: [
         "libkeymint_vts_test_utils",
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
new file mode 100644
index 0000000..e16a47b
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymint_2_se_provisioning_test"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include <cppbor_parse.h>
+#include <keymaster/cppcose/cppcose.h>
+#include <keymint_support/key_param_output.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+using std::array;
+using std::map;
+using std::shared_ptr;
+using std::vector;
+
+class SecureElementProvisioningTest : public testing::Test {
+  protected:
+    static void SetupTestSuite() {
+        auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+        for (auto& param : params) {
+            ASSERT_TRUE(AServiceManager_isDeclared(param.c_str()))
+                    << "IKeyMintDevice instance " << param << " found but not declared.";
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(param.c_str()));
+            auto keymint = IKeyMintDevice::fromBinder(binder);
+            ASSERT_NE(keymint, nullptr) << "Failed to get IKeyMintDevice instance " << param;
+
+            KeyMintHardwareInfo info;
+            ASSERT_TRUE(keymint->getHardwareInfo(&info).isOk());
+            ASSERT_EQ(keymints_.count(info.securityLevel), 0)
+                    << "There must be exactly one IKeyMintDevice with security level "
+                    << info.securityLevel;
+
+            keymints_[info.securityLevel] = std::move(keymint);
+        }
+    }
+
+    static map<SecurityLevel, shared_ptr<IKeyMintDevice>> keymints_;
+};
+
+map<SecurityLevel, shared_ptr<IKeyMintDevice>> SecureElementProvisioningTest::keymints_;
+
+TEST_F(SecureElementProvisioningTest, ValidConfigurations) {
+    // TEE is required
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    // StrongBox is optional
+    ASSERT_LE(keymints_.count(SecurityLevel::STRONGBOX), 1);
+}
+
+TEST_F(SecureElementProvisioningTest, TeeOnly) {
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    array<uint8_t, 16> challenge1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    array<uint8_t, 16> challenge2 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+    vector<uint8_t> rootOfTrust1;
+    Status result = tee->getRootOfTrust(challenge1, &rootOfTrust1);
+
+    // TODO: Remove the next line to require TEEs to succeed.
+    if (!result.isOk()) return;
+
+    ASSERT_TRUE(result.isOk());
+
+    // TODO:  Parse and validate rootOfTrust1 here
+
+    vector<uint8_t> rootOfTrust2;
+    result = tee->getRootOfTrust(challenge2, &rootOfTrust2);
+    ASSERT_TRUE(result.isOk());
+
+    // TODO:  Parse and validate rootOfTrust2 here
+
+    ASSERT_NE(rootOfTrust1, rootOfTrust2);
+
+    vector<uint8_t> rootOfTrust3;
+    result = tee->getRootOfTrust(challenge1, &rootOfTrust3);
+    ASSERT_TRUE(result.isOk());
+
+    ASSERT_EQ(rootOfTrust1, rootOfTrust3);
+
+    // TODO:  Parse and validate rootOfTrust3 here
+}
+
+TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = tee->getRootOfTrustChallenge(&challenge);
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()), ErrorCode::UNIMPLEMENTED);
+
+    result = tee->sendRootOfTrust({});
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()), ErrorCode::UNIMPLEMENTED);
+}
+
+TEST_F(SecureElementProvisioningTest, StrongBoxDoesNotImplementTeeMethods) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return;
+
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    vector<uint8_t> rootOfTrust;
+    Status result = sb->getRootOfTrust({}, &rootOfTrust);
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()), ErrorCode::UNIMPLEMENTED);
+}
+
+TEST_F(SecureElementProvisioningTest, UnimplementedTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return;  // Need a StrongBox to provision.
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = sb->getRootOfTrustChallenge(&challenge);
+    if (!result.isOk()) {
+        // Strongbox does not have to implement this feature if it has uses an alternative mechanism
+        // to provision the root of trust.  In that case it MUST return UNIMPLEMENTED, both from
+        // getRootOfTrustChallenge() and from sendRootOfTrust().
+        ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+                  ErrorCode::UNIMPLEMENTED);
+
+        result = sb->sendRootOfTrust({});
+        ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+                  ErrorCode::UNIMPLEMENTED);
+
+        SUCCEED() << "This Strongbox implementation does not use late root of trust delivery.";
+        return;
+    }
+}
+
+TEST_F(SecureElementProvisioningTest, ChallengeQualityTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return;  // Need a StrongBox to provision.
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge1;
+    Status result = sb->getRootOfTrustChallenge(&challenge1);
+    if (!result.isOk()) return;
+
+    array<uint8_t, 16> challenge2;
+    result = sb->getRootOfTrustChallenge(&challenge2);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_NE(challenge1, challenge2);
+
+    // TODO: When we add entropy testing in other relevant places in these tests, add it here, too,
+    // to verify that challenges appear to have adequate entropy.
+}
+
+TEST_F(SecureElementProvisioningTest, ProvisioningTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return;  // Need a StrongBox to provision.
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = sb->getRootOfTrustChallenge(&challenge);
+    if (!result.isOk()) return;
+
+    vector<uint8_t> rootOfTrust;
+    result = tee->getRootOfTrust(challenge, &rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+
+    // TODO: Verify COSE_Mac0 structure and content here.
+
+    result = sb->sendRootOfTrust(rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+
+    // Sending again must fail, because a new challenge is required.
+    result = sb->sendRootOfTrust(rootOfTrust);
+    ASSERT_FALSE(result.isOk());
+}
+
+TEST_F(SecureElementProvisioningTest, InvalidProvisioningTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) return;  // Need a StrongBox to provision.
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = sb->getRootOfTrustChallenge(&challenge);
+    if (!result.isOk()) return;
+
+    result = sb->sendRootOfTrust({});
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+              ErrorCode::VERIFICATION_FAILED);
+
+    vector<uint8_t> rootOfTrust;
+    result = tee->getRootOfTrust(challenge, &rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+
+    vector<uint8_t> corruptedRootOfTrust = rootOfTrust;
+    corruptedRootOfTrust[corruptedRootOfTrust.size() / 2]++;
+    result = sb->sendRootOfTrust(corruptedRootOfTrust);
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+              ErrorCode::VERIFICATION_FAILED);
+
+    // Now try the correct RoT
+    result = sb->sendRootOfTrust(rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+}
+
+}  // namespace aidl::android::hardware::security::keymint::test