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()