blob: 50511f231eba163947b04d0b97bc6bef0fc236ce [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 "cose/timestamp_updater.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/clock_interface.h"
#include "absl/time/simulated_clock.h"
#include "absl/time/time.h"
#include "async/async_context.h"
#include "cose/sig_structure.h"
#include "cose/simple_cms_parser.h"
#include "cose/timestamp_creator.h"
#include "crypto/default/hasher.h"
#include "crypto/timestamp_write_handler.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "testing/create_test_crypto_write_handler.h"
#include "tsp/parsed_timestamp_token.h"
#include "tsp/timestamp_verifier.h"
#include "tsp/verified_timestamp.h"
namespace credentio {
namespace {
using ::absl_testing::StatusIs;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::SizeIs;
constexpr absl::Time kTestTime = absl::FromUnixSeconds(1741403167);
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> CreateTimestampHandler(
absl::Clock* clock) {
return CreateTestCryptoWriteHandler({.clock = clock});
}
absl::StatusOr<std::string> UpdateTimestamp(
TimestampUpdater& updater, absl::string_view encoded_cose_sign1) {
std::string updated_encoded_cose_sign1(encoded_cose_sign1);
absl::Notification done;
absl::Status status;
updater.UpdateTimestamp(&updated_encoded_cose_sign1, AsyncContext(),
[&](absl::Status s) {
status = std::move(s);
done.Notify();
});
done.WaitForNotification();
if (!status.ok()) return status;
return updated_encoded_cose_sign1;
}
TEST(TimestampUpdater, UpdateTimestamp) {
// Create a timestamp creator.
absl::SimulatedClock clock;
clock.SetTime(kTestTime);
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> timestamp_handler =
CreateTimestampHandler(&clock);
ABSL_ASSERT_OK(timestamp_handler);
TimestampCreator timestamp_creator(timestamp_handler->get(),
&DefaultHasherFactory());
TimestampUpdater timestamp_updater(&timestamp_creator);
// Create a timestamp placeholder.
CoseSign1TaggedStructure to_be_updated{
.protected_header = "def",
.unprotected_header =
{
.sig_tst2 = TstContainer{.tst_tokens = {{.val = std::string(
1200, '\0')}}},
.pad = std::string(25, '\0'),
},
.signature = "abc",
};
std::string encoded_cose_sign1 =
EncodeCoseSign1TaggedStructure(to_be_updated);
// Update the timestamp.
absl::StatusOr<std::string> updated_cose_sign1 =
UpdateTimestamp(timestamp_updater, encoded_cose_sign1);
ABSL_ASSERT_OK(updated_cose_sign1);
EXPECT_EQ(updated_cose_sign1->size(), encoded_cose_sign1.size());
// Verify the updated timestamp.
TimestampVerifier verifier(/*tsa_roots=*/nullptr);
SimpleCmsParser parser;
absl::StatusOr<CoseSign1TaggedStructure> decoded =
DecodeCoseSign1TaggedStructure(*updated_cose_sign1);
ABSL_ASSERT_OK(decoded);
ASSERT_THAT(decoded->unprotected_header.sig_tst2->tst_tokens, SizeIs(1));
ASSERT_THAT(decoded->unprotected_header.sig_tst2->tst_tokens[0].val,
Not(IsEmpty()));
absl::StatusOr<std::unique_ptr<ParsedTimestampToken>> parsed_token =
parser.ParseTimestampToken(
decoded->unprotected_header.sig_tst2->tst_tokens[0].val);
ABSL_ASSERT_OK(parsed_token);
absl::StatusOr<VerifiedTimestamp> updated_verified_timestamp =
verifier.VerifyTimestampToken(**parsed_token);
ABSL_ASSERT_OK(updated_verified_timestamp);
EXPECT_EQ(updated_verified_timestamp->asserted_time(), kTestTime);
}
TEST(TimestampUpdater, UpdateTimestampNotEnoughSpace) {
// Create a timestamp creator.
absl::SimulatedClock clock;
clock.SetTime(kTestTime);
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> timestamp_handler =
CreateTimestampHandler(&clock);
ABSL_ASSERT_OK(timestamp_handler);
TimestampCreator timestamp_creator(timestamp_handler->get(),
&DefaultHasherFactory());
TimestampUpdater timestamp_updater(&timestamp_creator);
// Create a timestamp.
CoseSign1TaggedStructure cose_sign1;
EXPECT_THAT(UpdateTimestamp(timestamp_updater,
EncodeCoseSign1TaggedStructure(cose_sign1)),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Not enough space")));
}
} // namespace
} // namespace credentio