// Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "crypto/unexportable_key.h" #include #include "base/logging.h" #include "base/time/time.h" #include "crypto/scoped_mock_unexportable_key_provider.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace { const crypto::SignatureVerifier::SignatureAlgorithm kAllAlgorithms[] = { crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256, crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256, }; class UnexportableKeySigningTest : public testing::TestWithParam< std::tuple> {}; INSTANTIATE_TEST_SUITE_P(All, UnexportableKeySigningTest, testing::Combine(testing::ValuesIn(kAllAlgorithms), testing::Bool())); TEST_P(UnexportableKeySigningTest, RoundTrip) { const crypto::SignatureVerifier::SignatureAlgorithm algo = std::get<0>(GetParam()); const bool mock_enabled = std::get<1>(GetParam()); switch (algo) { case crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256: LOG(INFO) << "ECDSA P-256, mock=" << mock_enabled; break; case crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256: LOG(INFO) << "RSA, mock=" << mock_enabled; break; default: ASSERT_TRUE(false); } SCOPED_TRACE(static_cast(algo)); SCOPED_TRACE(mock_enabled); absl::optional mock; if (mock_enabled) { mock.emplace(); } const crypto::SignatureVerifier::SignatureAlgorithm algorithms[] = {algo}; std::unique_ptr provider = crypto::GetUnexportableKeyProvider(); if (!provider) { LOG(INFO) << "Skipping test because of lack of hardware support."; return; } if (!provider->SelectAlgorithm(algorithms)) { LOG(INFO) << "Skipping test because of lack of support for this key type."; return; } const base::TimeTicks generate_start = base::TimeTicks::Now(); std::unique_ptr key = provider->GenerateSigningKeySlowly(algorithms); ASSERT_TRUE(key); LOG(INFO) << "Generation took " << (base::TimeTicks::Now() - generate_start); ASSERT_EQ(key->Algorithm(), algo); const std::vector wrapped = key->GetWrappedKey(); const std::vector spki = key->GetSubjectPublicKeyInfo(); const uint8_t msg[] = {1, 2, 3, 4}; const base::TimeTicks sign_start = base::TimeTicks::Now(); const absl::optional> sig = key->SignSlowly(msg); LOG(INFO) << "Signing took " << (base::TimeTicks::Now() - sign_start); ASSERT_TRUE(sig); crypto::SignatureVerifier verifier; ASSERT_TRUE(verifier.VerifyInit(algo, *sig, spki)); verifier.VerifyUpdate(msg); ASSERT_TRUE(verifier.VerifyFinal()); const base::TimeTicks import2_start = base::TimeTicks::Now(); std::unique_ptr key2 = provider->FromWrappedSigningKeySlowly(wrapped); ASSERT_TRUE(key2); LOG(INFO) << "Import took " << (base::TimeTicks::Now() - import2_start); const base::TimeTicks sign2_start = base::TimeTicks::Now(); const absl::optional> sig2 = key->SignSlowly(msg); LOG(INFO) << "Signing took " << (base::TimeTicks::Now() - sign2_start); ASSERT_TRUE(sig2); crypto::SignatureVerifier verifier2; ASSERT_TRUE(verifier2.VerifyInit(algo, *sig2, spki)); verifier2.VerifyUpdate(msg); ASSERT_TRUE(verifier2.VerifyFinal()); } } // namespace