Merge "Fix formatting, use consistent comment styles, and document more fields." into main
diff --git a/bluetooth/ranging/aidl/vts/Android.bp b/bluetooth/ranging/aidl/vts/Android.bp
index 9984ce8..bcae5d0 100644
--- a/bluetooth/ranging/aidl/vts/Android.bp
+++ b/bluetooth/ranging/aidl/vts/Android.bp
@@ -17,7 +17,7 @@
         "libutils",
     ],
     static_libs: [
-        "android.hardware.bluetooth.ranging-V1-ndk",
+        "android.hardware.bluetooth.ranging-V2-ndk",
         "libbluetooth-types",
     ],
     test_config: "VtsHalBluetoothRangingTargetTest.xml",
diff --git a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
index 702df95..4510f24 100644
--- a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
+++ b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
@@ -30,12 +30,15 @@
 using aidl::android::hardware::bluetooth::ranging::
     BnBluetoothChannelSoundingSessionCallback;
 using aidl::android::hardware::bluetooth::ranging::ChannelSoudingRawData;
+using aidl::android::hardware::bluetooth::ranging::ChannelSoundingProcedureData;
+using aidl::android::hardware::bluetooth::ranging::Config;
 using aidl::android::hardware::bluetooth::ranging::CsSecurityLevel;
 using aidl::android::hardware::bluetooth::ranging::IBluetoothChannelSounding;
 using aidl::android::hardware::bluetooth::ranging::
     IBluetoothChannelSoundingSession;
 using aidl::android::hardware::bluetooth::ranging::
     IBluetoothChannelSoundingSessionCallback;
+using aidl::android::hardware::bluetooth::ranging::ProcedureEnableConfig;
 using aidl::android::hardware::bluetooth::ranging::RangingResult;
 using aidl::android::hardware::bluetooth::ranging::Reason;
 using aidl::android::hardware::bluetooth::ranging::ResultType;
@@ -43,6 +46,12 @@
 using aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
 using ndk::ScopedAStatus;
 
+enum class RangingHalVersion : uint8_t {
+  V_UNAVAILABLE = 0,
+  V_1,
+  V_2,
+};
+
 class BluetoothChannelSoundingSessionCallback
     : public BnBluetoothChannelSoundingSessionCallback {
  public:
@@ -80,6 +89,8 @@
     ALOGI("SetUp Ranging Test");
     bluetooth_channel_sounding_ = IBluetoothChannelSounding::fromBinder(
         ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    hal_version_ = GetRangingHalVersion();
+    ASSERT_GT(hal_version_, RangingHalVersion::V_UNAVAILABLE);
     ASSERT_NE(bluetooth_channel_sounding_, nullptr);
   }
 
@@ -95,6 +106,8 @@
   ScopedAStatus getSupportedSessionTypes(
       std::optional<std::vector<SessionType>>* _aidl_return);
   ScopedAStatus getMaxSupportedCsSecurityLevel(CsSecurityLevel* _aidl_return);
+  ScopedAStatus getSupportedCsSecurityLevels(
+      std::vector<CsSecurityLevel>* _aidl_return);
   ScopedAStatus openSession(
       const BluetoothChannelSoundingParameters& in_params,
       const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
@@ -111,6 +124,30 @@
     return status;
   }
 
+  RangingHalVersion GetRangingHalVersion() {
+    int32_t aidl_version = 0;
+    if (bluetooth_channel_sounding_ == nullptr) {
+      return RangingHalVersion::V_UNAVAILABLE;
+    }
+    auto aidl_ret_val =
+        bluetooth_channel_sounding_->getInterfaceVersion(&aidl_version);
+    if (!aidl_ret_val.isOk()) {
+      return RangingHalVersion::V_UNAVAILABLE;
+    }
+    switch (aidl_version) {
+      case 1:
+        return RangingHalVersion::V_1;
+      case 2:
+        return RangingHalVersion::V_2;
+      default:
+        return RangingHalVersion::V_UNAVAILABLE;
+    }
+    return RangingHalVersion::V_UNAVAILABLE;
+  }
+
+ public:
+  RangingHalVersion hal_version_ = RangingHalVersion::V_UNAVAILABLE;
+
  private:
   std::shared_ptr<IBluetoothChannelSounding> bluetooth_channel_sounding_;
 };
@@ -130,6 +167,13 @@
   return bluetooth_channel_sounding_->getMaxSupportedCsSecurityLevel(
       _aidl_return);
 }
+
+ScopedAStatus BluetoothRangingTest::getSupportedCsSecurityLevels(
+    std::vector<CsSecurityLevel>* _aidl_return) {
+  return bluetooth_channel_sounding_->getSupportedCsSecurityLevels(
+      _aidl_return);
+}
+
 ScopedAStatus BluetoothRangingTest::openSession(
     const BluetoothChannelSoundingParameters& in_params,
     const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
@@ -155,11 +199,25 @@
 }
 
 TEST_P(BluetoothRangingTest, GetMaxSupportedCsSecurityLevel) {
+  if (hal_version_ > RangingHalVersion::V_1) {
+    GTEST_SKIP();
+  }
   CsSecurityLevel security_level;
   ScopedAStatus status = getMaxSupportedCsSecurityLevel(&security_level);
   ASSERT_TRUE(status.isOk());
 }
 
+TEST_P(BluetoothRangingTest, GetSupportedCsSecurityLevels) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::vector<CsSecurityLevel> supported_security_levels;
+  ScopedAStatus status =
+      getSupportedCsSecurityLevels(&supported_security_levels);
+  ASSERT_GT(static_cast<uint8_t>(supported_security_levels.size()), 0);
+  ASSERT_TRUE(status.isOk());
+}
+
 TEST_P(BluetoothRangingTest, OpenSession) {
   BluetoothChannelSoundingParameters params;
   std::shared_ptr<BluetoothChannelSoundingSessionCallback> callback = nullptr;
@@ -205,6 +263,9 @@
 }
 
 TEST_P(BluetoothRangingTest, WriteRawData) {
+  if (hal_version_ > RangingHalVersion::V_1) {
+    GTEST_SKIP();
+  }
   std::shared_ptr<IBluetoothChannelSoundingSession> session;
   auto status = initBluetoothChannelSoundingSession(&session);
   ASSERT_TRUE(status.isOk());
@@ -215,6 +276,62 @@
   }
 }
 
+TEST_P(BluetoothRangingTest, WriteProcedureData) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    ChannelSoundingProcedureData procedure_data;
+    status = session->writeProcedureData(procedure_data);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, UpdateChannelSoundingConfig) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    Config config;
+    status = session->updateChannelSoundingConfig(config);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, UpdateProcedureEnableConfig) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    ProcedureEnableConfig procedure_enable_config;
+    status = session->updateProcedureEnableConfig(procedure_enable_config);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, UpdateBleConnInterval) {
+  if (hal_version_ < RangingHalVersion::V_2) {
+    GTEST_SKIP();
+  }
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    int ble_conn_interval = 10;
+    status = session->updateBleConnInterval(ble_conn_interval);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
 TEST_P(BluetoothRangingTest, CloseSession) {
   std::shared_ptr<IBluetoothChannelSoundingSession> session;
   auto status = initBluetoothChannelSoundingSession(&session);
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.h b/graphics/composer/aidl/vts/RenderEngineVts.h
index bbe508f..6553720 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.h
+++ b/graphics/composer/aidl/vts/RenderEngineVts.h
@@ -51,9 +51,10 @@
 
   private:
     common::PixelFormat mFormat;
-    std::vector<::android::renderengine::LayerSettings> mCompositionLayers;
     std::unique_ptr<::android::renderengine::RenderEngine> mRenderEngine;
-    std::vector<::android::renderengine::LayerSettings> mRenderLayers;
+    // Delete RenderEngine layers before RenderEngine -- ExternalTexture holds a reference to
+    // RenderEngine.
+    std::vector<::android::renderengine::LayerSettings> mCompositionLayers;
     ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
 
     DisplaySettings mDisplaySettings;
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
index b34e4f2..1ffd274 100644
--- a/nfc/aidl/Android.bp
+++ b/nfc/aidl/Android.bp
@@ -33,8 +33,9 @@
             enabled: false,
         },
         java: {
-            sdk_version: "module_current",
             enabled: false,
+            sdk_version: "module_current",
+            min_sdk_version: "35",
         },
         ndk: {
             enabled: true,
@@ -42,6 +43,7 @@
                 "//apex_available:platform",
                 "com.android.nfcservices",
             ],
+            min_sdk_version: "35",
         },
         rust: {
             enabled: true,
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index ff2393c..0197141 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -104,6 +104,7 @@
     ],
 }
 
+// The following target declares the latest version of KeyMint.
 prebuilt_etc {
     name: "android.hardware.hardware_keystore.xml",
     sub_dir: "permissions",
@@ -111,6 +112,24 @@
     src: "android.hardware.hardware_keystore.xml",
 }
 
+// The following targets (and underlying XML files) declare specific
+// versions of KeyMint.  Vendors should use the version that matches the
+// version of the KeyMint HAL that the device implements.
+
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore_V1.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore_V1.xml",
+}
+
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore_V2.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore_V2.xml",
+}
+
 prebuilt_etc {
     name: "android.hardware.hardware_keystore_V3.xml",
     sub_dir: "permissions",
@@ -118,6 +137,13 @@
     src: "android.hardware.hardware_keystore_V3.xml",
 }
 
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore_V4.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore_V4.xml",
+}
+
 rust_library {
     name: "libkmr_hal_nonsecure",
     crate_name: "kmr_hal_nonsecure",
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore_V1.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore_V1.xml
new file mode 100644
index 0000000..e5a9345
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore_V1.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="100" />
+</permissions>
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore_V2.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore_V2.xml
new file mode 100644
index 0000000..2ebf1fe
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore_V2.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="200" />
+</permissions>
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore_V4.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore_V4.xml
new file mode 100644
index 0000000..1ab2133
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore_V4.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="400" />
+</permissions>
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 51afa12..0ce6a15 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -83,6 +83,16 @@
 // additional overhead, for the digest algorithmIdentifier required by PKCS#1.
 const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
 
+// Determine whether the key description is for an asymmetric key.
+bool is_asymmetric(const AuthorizationSet& key_desc) {
+    auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
+    if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 size_t count_tag_invalid_entries(const std::vector<KeyParameter>& authorizations) {
     return std::count_if(authorizations.begin(), authorizations.end(),
                          [](const KeyParameter& e) -> bool { return e.tag == Tag::INVALID; });
@@ -418,11 +428,14 @@
     vector<Certificate> attest_cert_chain;
     // If an attestation is requested, but the system is RKP-only, we need to supply an explicit
     // attestation key. Else the result is a key without an attestation.
-    // If the RKP-only value is undeterminable (i.e., when running on GSI), generate and use the
-    // attest key anyways. In the case that using an attest key is not supported
-    // (shouldSkipAttestKeyTest), assume the device has factory keys (so not RKP-only).
+    // - If the RKP-only value is undeterminable (i.e., when running on GSI), generate and use the
+    //   `ATTEST_KEY` anyways.
+    // - In the case that using an `ATTEST_KEY` is not supported
+    //   (shouldSkipAttestKeyTest), assume the device has factory keys (so not RKP-only).
+    // - If the key being generated is a symmetric key (from test cases that check that the
+    //   attestation parameters are correctly ignored), don't try to use an `ATTEST_KEY`.
     if (isRkpOnly().value_or(true) && key_desc.Contains(TAG_ATTESTATION_CHALLENGE) &&
-        !shouldSkipAttestKeyTest()) {
+        !shouldSkipAttestKeyTest() && is_asymmetric(key_desc)) {
         AuthorizationSet attest_key_desc =
                 AuthorizationSetBuilder().EcdsaKey(EcCurve::P_256).AttestKey().SetDefaultValidity();
         attest_key.emplace();
@@ -462,10 +475,7 @@
         *key_characteristics = std::move(creationResult.keyCharacteristics);
         *cert_chain = std::move(creationResult.certificateChain);
 
-        auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
-        EXPECT_TRUE(algorithm);
-        if (algorithm &&
-            (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
+        if (is_asymmetric(key_desc)) {
             EXPECT_GE(cert_chain->size(), 1);
             if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
                 if (attest_key) {
@@ -506,10 +516,7 @@
         *key_characteristics = std::move(creationResult.keyCharacteristics);
         cert_chain_ = std::move(creationResult.certificateChain);
 
-        auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
-        EXPECT_TRUE(algorithm);
-        if (algorithm &&
-            (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
+        if (is_asymmetric(key_desc)) {
             EXPECT_GE(cert_chain_.size(), 1);
             if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1);
         } else {
@@ -554,10 +561,7 @@
         for (auto& entry : key_characteristics_) {
             allAuths.push_back(AuthorizationSet(entry.authorizations));
         }
-        auto algorithm = allAuths.GetTagValue(TAG_ALGORITHM);
-        EXPECT_TRUE(algorithm);
-        if (algorithm &&
-            (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
+        if (is_asymmetric(allAuths)) {
             EXPECT_GE(cert_chain_.size(), 1);
         } else {
             // For symmetric keys there should be no certificates.
@@ -2228,6 +2232,33 @@
 
 namespace {
 
+std::optional<std::string> validateP256Point(const std::vector<uint8_t>& x_buffer,
+                                             const std::vector<uint8_t>& y_buffer) {
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    if (group.get() == nullptr) {
+        return "Error creating EC group by curve name for prime256v1";
+    }
+
+    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+    BIGNUM_Ptr x(BN_bin2bn(x_buffer.data(), x_buffer.size(), nullptr));
+    BIGNUM_Ptr y(BN_bin2bn(y_buffer.data(), y_buffer.size(), nullptr));
+    if (!EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(), nullptr)) {
+        return "Failed to set affine coordinates.";
+    }
+    if (!EC_POINT_is_on_curve(group.get(), point.get(), nullptr)) {
+        return "Point is not on curve.";
+    }
+    if (EC_POINT_is_at_infinity(group.get(), point.get())) {
+        return "Point is at infinity.";
+    }
+    const auto* generator = EC_GROUP_get0_generator(group.get());
+    if (!EC_POINT_cmp(group.get(), generator, point.get(), nullptr)) {
+        return "Point is equal to generator.";
+    }
+
+    return std::nullopt;
+}
+
 void check_cose_key(const vector<uint8_t>& data, bool testMode) {
     auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
     ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
@@ -2261,6 +2292,24 @@
                              "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
                              "\\}"));
     }
+
+    ASSERT_TRUE(parsedPayload->asMap()) << "CBOR item was not a map";
+
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X))
+            << "CBOR map did not contain x coordinate of public key";
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X)->asBstr())
+            << "x coordinate of public key was not a bstr";
+    const auto& x = parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_X)->asBstr()->value();
+
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y))
+            << "CBOR map did not contain y coordinate of public key";
+    ASSERT_TRUE(parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y)->asBstr())
+            << "y coordinate of public key was not a bstr";
+    const auto& y = parsedPayload->asMap()->get(CoseKey::Label::PUBKEY_Y)->asBstr()->value();
+
+    auto errorMessage = validateP256Point(x, y);
+    EXPECT_EQ(errorMessage, std::nullopt)
+            << *errorMessage << " x: " << bin2hex(x) << " y: " << bin2hex(y);
 }
 
 }  // namespace
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 5467679..b9c742a 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -416,6 +416,32 @@
     check_maced_pubkey(macedPubKey, testMode, nullptr);
 }
 
+/**
+ * Generate and validate at most 2**16 production-mode keys. This aims to catch issues that do not
+ * deterministically show up. In practice, this will test far fewer keys, but a certain number are
+ * tested at a minimum.
+ */
+TEST_P(GenerateKeyTests, generateManyEcdsaP256KeysInProdMode) {
+    const auto start = std::chrono::steady_clock::now();
+    const auto time_bound = std::chrono::seconds(5);
+    const auto upper_bound = 1 << 16;
+    const auto lower_bound = 1 << 8;
+    for (auto iteration = 0; iteration < upper_bound; iteration++) {
+        MacedPublicKey macedPubKey;
+        bytevec privateKeyBlob;
+        bool testMode = false;
+        auto status =
+                provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+        ASSERT_TRUE(status.isOk());
+        vector<uint8_t> coseKeyData;
+        check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+        const auto current_time = std::chrono::steady_clock::now() - start;
+        if (iteration >= lower_bound && current_time >= time_bound) {
+            break;
+        }
+    }
+}
+
 class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
   protected:
     CertificateRequestTestBase()