blob: 0c6e0aa3c328b97789929ea4a84d911da3120b6d [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 "claim/timestamp_updater.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/status/status.h"
#include "absl/status/status_macros.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 "constants/labels.h"
#include "cose/sig_structure.h"
#include "cose/timestamp_creator.h"
#include "crypto/crypto_read_handler.h"
#include "crypto/default/default_crypto_read_handler.h"
#include "crypto/default/hasher.h"
#include "crypto/hash.h"
#include "crypto/timestamp_write_handler.h"
#include "gmock/gmock.h"
#include "google/protobuf/timestamp.pb.h"
#include "gtest/gtest.h"
#include "jumbf/test_utils.h"
#include "proto/validation_result.pb.h"
#include "testing/create_test_crypto_write_handler.h"
#include "testing/manifest_store_test_utils.h"
#include "validator/manifest_store_validator_impl.h"
#include "validator/validator_options.h"
namespace credentio {
namespace {
using ::absl_testing::IsOkAndHolds;
constexpr absl::Time kTestTime = absl::FromUnixSeconds(1741403167);
absl::StatusOr<absl::Time> ValidateAndGetTime(
absl::string_view manifest_store) {
ABSL_ASSIGN_OR_RETURN(
std::unique_ptr<CryptoReadHandler> crypto_read_handler,
CreateDefaultCryptoReadHandler({
.tsa_trust_anchors_pem = DefaultTestPki().root_ca.cert_pem,
.skip_claim_signer_trust_checks_for_test = true,
}));
ManifestStoreValidatorImpl validator(ValidatorOptions{
.crypto_read_handler = std::move(crypto_read_handler),
});
ABSL_ASSIGN_OR_RETURN(std::unique_ptr<PartialValidationResultProto> result,
validator.Validate(manifest_store));
const google::protobuf::Timestamp& ts =
result->active_manifest().claim().signature_info().timestamping_time();
return absl::FromUnixSeconds(ts.seconds()) + absl::Nanoseconds(ts.nanos());
}
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> CreateTimestampHandler(
absl::Clock* clock) {
return CreateTestCryptoWriteHandler({.clock = clock});
}
absl::StatusOr<std::string> InsertTimestamp(ClaimTimestampUpdater& updater,
absl::string_view manifest_store) {
std::string updated_manifest_store(manifest_store);
absl::Notification done;
absl::Status status;
updater.InsertTimestamp(&updated_manifest_store, AsyncContext(),
[&](absl::Status s) {
status = std::move(s);
done.Notify();
});
done.WaitForNotification();
if (!status.ok()) return status;
return updated_manifest_store;
}
TEST(ClaimTimestampUpdater, InsertTimestampStandardManifest) {
absl::StatusOr<std::string> manifest_store =
CreateSimpleManifestStoreBytes({.disable_timestamping = true});
ABSL_ASSERT_OK(manifest_store);
absl::SimulatedClock clock;
clock.SetTime(kTestTime);
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> timestamp_handler =
CreateTimestampHandler(&clock);
ABSL_ASSERT_OK(timestamp_handler);
auto timestamp_creator = std::make_unique<TimestampCreator>(
timestamp_handler->get(), &DefaultHasherFactory());
ClaimTimestampUpdater updater(std::move(timestamp_creator));
absl::StatusOr<std::string> updated_manifest_store =
InsertTimestamp(updater, *manifest_store);
ABSL_ASSERT_OK(updated_manifest_store);
EXPECT_THAT(ValidateAndGetTime(*updated_manifest_store),
IsOkAndHolds(kTestTime));
EXPECT_EQ(updated_manifest_store->size(), manifest_store->size());
}
TEST(ClaimTimestampUpdater, InsertTimestampInUpdateManifest) {
absl::SimulatedClock clock;
clock.SetTime(kTestTime);
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> timestamp_handler =
CreateTimestampHandler(&clock);
ABSL_ASSERT_OK(timestamp_handler);
std::string timestamp_placeholder(
(*timestamp_handler)
->max_timestamp_byte_size(DefaultHasherFactory().algorithm()),
'\0');
CoseSign1TaggedStructure cose_sign1{
.unprotected_header =
{.sig_tst2 =
TstContainer{.tst_tokens = {{.val = timestamp_placeholder}}}},
.signature = "abc",
};
std::string claim_signature = jumbf::EncodeSuperBox(
kClaimSignatureUuid, kClaimSignatureLabel,
{jumbf::EncodeCborBox(EncodeCoseSign1TaggedStructure(cose_sign1))});
std::string manifest = jumbf::EncodeSuperBox(
kUpdateManifestUuid, "update_manifest", {claim_signature});
std::string manifest_store = jumbf::EncodeSuperBox(
kManifestStoreUuid, kManifestStoreLabel, {manifest});
auto timestamp_creator = std::make_unique<TimestampCreator>(
timestamp_handler->get(), &DefaultHasherFactory());
ClaimTimestampUpdater updater(std::move(timestamp_creator));
absl::StatusOr<std::string> updated_manifest_store =
InsertTimestamp(updater, manifest_store);
ABSL_ASSERT_OK(updated_manifest_store);
EXPECT_EQ(updated_manifest_store->size(), manifest_store.size());
}
TEST(ClaimTimestampUpdater, TimestampExistsNoOp) {
absl::SimulatedClock clock;
clock.SetTime(kTestTime);
absl::StatusOr<std::string> manifest_store = CreateSimpleManifestStoreBytes(
{.clock = &clock, .disable_timestamping = false});
ABSL_ASSERT_OK(manifest_store);
clock.AdvanceTime(absl::Seconds(100));
absl::StatusOr<std::unique_ptr<TimestampWriteHandler>> timestamp_handler =
CreateTimestampHandler(&clock);
ABSL_ASSERT_OK(timestamp_handler);
auto timestamp_creator = std::make_unique<TimestampCreator>(
timestamp_handler->get(), &DefaultHasherFactory());
ClaimTimestampUpdater updater(std::move(timestamp_creator));
absl::StatusOr<std::string> updated_manifest_store =
InsertTimestamp(updater, *manifest_store);
ABSL_ASSERT_OK(updated_manifest_store);
EXPECT_EQ(*updated_manifest_store, *manifest_store);
}
} // namespace
} // namespace credentio