blob: caaa26c80b70f9457040f81dfea0a2e70cf15380 [file]
// Copyright 2026 Google LLC
//
// 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
//
// https://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.
//
#include "testing/create_test_crypto_write_handler.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/notification.h"
#include "absl/time/simulated_clock.h"
#include "absl/time/time.h"
#include "cose/simple_cms_parser.h"
#include "crypto/algorithms.h"
#include "crypto/crypto_write_handler.h"
#include "crypto/default/trust_store.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "openssl/pki/verify.h"
#include "testing/local_key_crypto_write_handler.h"
#include "testing/test_validation_tracker.h"
#include "tsp/parsed_timestamp_token.h"
#include "tsp/timestamp_verifier.h"
#include "tsp/verified_timestamp.h"
namespace credentio {
namespace {
using ::absl_testing::IsOk;
using ::absl_testing::StatusIs;
using ::testing::ElementsAreArray;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::Not;
absl::StatusOr<std::string> GetTimestamp(CryptoWriteHandler& handler,
HashAlgorithm hash_algorithm,
absl::string_view hashed_message) {
absl::Notification done;
absl::StatusOr<std::string> result;
handler.CreateTimestamp(hash_algorithm, std::string(hashed_message),
/*options=*/{},
[&result, &done](absl::StatusOr<std::string> res) {
result = std::move(res);
done.Notify();
});
done.WaitForNotification();
return result;
}
TEST(CreateTestCryptoWriteHandlerTest, CreateTimestamp) {
absl::SimulatedClock clock;
absl::Time now = absl::FromUnixSeconds(1739221301); // within validity period
clock.SetTime(now);
std::string message_imprint = "message_imprint";
absl::StatusOr<std::unique_ptr<CryptoWriteHandler>> writer =
CreateTestCryptoWriteHandler({.clock = &clock});
ABSL_ASSERT_OK(writer);
absl::StatusOr<std::string> created_timestamp =
GetTimestamp(**writer, HashAlgorithm::kSha384, message_imprint);
ABSL_ASSERT_OK(created_timestamp);
absl::StatusOr<std::unique_ptr<bssl::VerifyTrustStore>> trust_store =
LoadTrustStore(DefaultTestPki().root_ca.cert_pem);
ABSL_ASSERT_OK(trust_store);
TimestampVerifier verifier(trust_store->get());
SimpleCmsParser parser;
TestValidationTracker t;
absl::StatusOr<std::unique_ptr<ParsedTimestampToken>> parsed_token =
parser.ParseTimestampToken(*created_timestamp);
ABSL_ASSERT_OK(parsed_token);
absl::StatusOr<VerifiedTimestamp> verified_timestamp =
verifier.VerifyTimestampToken(**parsed_token);
ABSL_ASSERT_OK(verified_timestamp);
ASSERT_THAT(t.GetFailureStatuses(), IsEmpty());
EXPECT_EQ(verified_timestamp->message_imprint_hash(), message_imprint);
EXPECT_EQ(verified_timestamp->asserted_time(), now);
}
TEST(CreateTestCryptoWriteHandlerTest, HasCertChainAndOcspResponse) {
absl::StatusOr<std::unique_ptr<CryptoWriteHandler>> writer =
CreateTestCryptoWriteHandler({});
ABSL_ASSERT_OK(writer);
EXPECT_THAT((*writer)->GetSigner().certificate_chain(), Not(IsEmpty()));
EXPECT_THAT((*writer)->GetSigner().ocsp_responses(), Not(IsEmpty()));
}
TEST(CreateTestCryptoWriteHandlerTest,
UsesConfiguredCertChainAndOcspResponses) {
LocalKeyClaimSignerCredentials credentials = TestClaimSignerCredentials();
credentials.ocsp_responses.clear();
absl::StatusOr<std::unique_ptr<CryptoWriteHandler>> writer =
CreateTestCryptoWriteHandler({.claim_signer = std::move(credentials)});
ABSL_ASSERT_OK(writer);
EXPECT_THAT((*writer)->GetSigner().certificate_chain(),
ElementsAreArray(TestClaimSignerCredentials().certificate_chain));
EXPECT_THAT((*writer)->GetSigner().ocsp_responses(), IsEmpty());
}
TEST(CreateTestCryptoWriteHandlerTest, UsesConfiguredSigningKey) {
// Any other valid EC P-256 key will do; reuse the TSA's.
LocalKeyClaimSignerCredentials credentials = TestClaimSignerCredentials();
credentials.key_pem = TestTsaCredentials().key_pem;
absl::StatusOr<std::unique_ptr<CryptoWriteHandler>> writer =
CreateTestCryptoWriteHandler({.claim_signer = std::move(credentials)});
ABSL_ASSERT_OK(writer);
absl::StatusOr<std::unique_ptr<CryptoWriteHandler>> default_writer =
CreateTestCryptoWriteHandler({});
ABSL_ASSERT_OK(default_writer);
absl::StatusOr<SignResponse> response =
(*writer)->GetSigner().Sign("to_be_signed");
ABSL_ASSERT_OK(response);
absl::StatusOr<SignResponse> default_response =
(*default_writer)->GetSigner().Sign("to_be_signed");
ABSL_ASSERT_OK(default_response);
EXPECT_NE(response->signature, default_response->signature);
}
TEST(CreateTestCryptoWriteHandlerTest, UsesConfiguredTsa) {
absl::SimulatedClock clock;
clock.SetTime(absl::FromUnixSeconds(1739221301)); // within validity period
absl::StatusOr<std::unique_ptr<CryptoWriteHandler>> writer =
CreateTestCryptoWriteHandler(
{.clock = &clock, .tsa = TestTsaCredentials()});
ABSL_ASSERT_OK(writer);
EXPECT_THAT(GetTimestamp(**writer, HashAlgorithm::kSha384, "message_imprint"),
IsOk());
}
TEST(CreateTestCryptoWriteHandlerTest,
RejectsIncompleteClaimSignerCredentials) {
EXPECT_THAT(CreateTestCryptoWriteHandler({.claim_signer = {{}}}),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Claim signer key")));
LocalKeyClaimSignerCredentials no_chain = TestClaimSignerCredentials();
no_chain.certificate_chain.clear();
EXPECT_THAT(
CreateTestCryptoWriteHandler({.claim_signer = std::move(no_chain)}),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Claim signer certificate chain")));
}
TEST(CreateTestCryptoWriteHandlerTest, RejectsIncompleteTsaCredentials) {
EXPECT_THAT(
CreateTestCryptoWriteHandler({.tsa = {{}}}),
StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("TSA key")));
LocalKeyTsaCredentials no_cert = TestTsaCredentials();
no_cert.cert_pem.clear();
EXPECT_THAT(CreateTestCryptoWriteHandler({.tsa = std::move(no_cert)}),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("TSA certificate")));
}
} // namespace
} // namespace credentio