| // 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/manifest_store_test_utils.h" | |
| #include <memory> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_macros.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/str_join.h" | |
| #include "absl/strings/string_view.h" | |
| #include "claim/local_signer.h" | |
| #include "claim/validator.h" | |
| #include "cose/verifier.h" | |
| #include "crypto/crypto_read_handler.h" | |
| #include "crypto/crypto_write_handler.h" | |
| #include "crypto/default/default_crypto_read_handler.h" | |
| #include "crypto/default/hasher.h" | |
| #include "generator/generator.h" | |
| #include "generator/generator_factory.h" | |
| #include "jumbf/box.h" | |
| #include "jumbf/parse.h" | |
| #include "proto/generator.pb.h" | |
| #include "proto/generator_info.pb.h" | |
| #include "proto/manifest.pb.h" | |
| #include "proto/validation_result.pb.h" | |
| #include "testing/create_test_crypto_write_handler.h" | |
| #include "testing/proto_test_utils.h" | |
| #include "testing/test_validation_tracker.h" | |
| #include "validator/manifest_store_validator_impl.h" | |
| namespace credentio { | |
| absl::StatusOr<std::string> CreateSimpleManifestStoreBytes( | |
| const SimpleManifestStoreOptions& options) { | |
| ABSL_ASSIGN_OR_RETURN( | |
| std::unique_ptr<CryptoWriteHandler> crypto_write_handler, | |
| CreateTestCryptoWriteHandler({ | |
| .clock = options.clock, | |
| .disable_timestamping = options.disable_timestamping, | |
| })); | |
| LocalClaimSigner claim_signer(crypto_write_handler.get(), | |
| &DefaultHasherFactory()); | |
| GeneratorInfo generator_info; | |
| if (options.generator_info.has_value()) { | |
| generator_info = *options.generator_info; | |
| } else { | |
| generator_info.set_name("Test C2PA Generator"); | |
| } | |
| ABSL_ASSIGN_OR_RETURN( | |
| std::unique_ptr<ManifestStoreGenerator> manifest_store_generator, | |
| CreateGenerator({ | |
| .generator_info = std::move(generator_info), | |
| .signing_claim_signer = &claim_signer, | |
| .template_claim_signer = &claim_signer, | |
| .uuid_generator = options.uuid_generator, | |
| })); | |
| auto request = credentio_testing::ParseTextProtoOrDie< | |
| GenerateManifestStoreRequest>(R"pb( | |
| instance_id: "12345678-1234-1234-1234-123456789012" | |
| hard_binding { | |
| box_hash { | |
| alg: "some alg" | |
| boxes { names: "some name" names: "other name" hash: "some hash" } | |
| } | |
| } | |
| actions { | |
| created { | |
| action_metadata { | |
| software_agent { name: "test generator" } | |
| description: "created for testing" | |
| } | |
| digital_source_type: "https://cv.iptc.org/newscodes/digitalsourcetype/computationalCapture" | |
| } | |
| } | |
| )pb"); | |
| ABSL_ASSIGN_OR_RETURN( | |
| auto generated, manifest_store_generator->GenerateManifestStore(request)); | |
| return std::string(generated.manifest_store()); | |
| } | |
| absl::StatusOr<std::unique_ptr<PartialValidationResultProto>> | |
| ValidateManifestStore(absl::string_view manifest_store_bytes) { | |
| ABSL_ASSIGN_OR_RETURN( | |
| std::unique_ptr<CryptoReadHandler> crypto_read_handler, | |
| CreateDefaultCryptoReadHandler({ | |
| .trust_environment = CryptoReadHandler::TrustEnvironment::kAny, | |
| })); | |
| ManifestStoreValidatorImpl validator({ | |
| .crypto_read_handler = std::move(crypto_read_handler), | |
| }); | |
| return validator.Validate(manifest_store_bytes); | |
| } | |
| absl::StatusOr<Claim> ValidateClaim(absl::string_view manifest_store_bytes) { | |
| ABSL_ASSIGN_OR_RETURN(auto manifest_store_box, | |
| jumbf::ConsumeSuperBox(&manifest_store_bytes, 9)); | |
| ABSL_ASSIGN_OR_RETURN( | |
| std::unique_ptr<CryptoReadHandler> crypto_read_handler, | |
| CreateDefaultCryptoReadHandler({ | |
| .trust_environment = CryptoReadHandler::TrustEnvironment::kAny, | |
| })); | |
| std::unique_ptr<CoseVerifier> cose_verifier = CreateCoseVerifier( | |
| {.crypto_read_handler = std::move(crypto_read_handler)}); | |
| ClaimValidatorImpl validator(cose_verifier.get()); | |
| TestValidationTracker validation_tracker; | |
| if (manifest_store_box.contents.empty()) { | |
| return absl::InvalidArgumentError("Manifest store is empty"); | |
| } | |
| if (!manifest_store_box.contents.back().Holds<jumbf::SuperBox>()) { | |
| return absl::InvalidArgumentError("Last box is not a super box"); | |
| } | |
| jumbf::SuperBox manifest_box = | |
| manifest_store_box.contents.back().Get<jumbf::SuperBox>(); | |
| auto result = validator.Validate(manifest_box, validation_tracker.tracker()); | |
| if (!validation_tracker.GetFailures().empty()) { | |
| return absl::InvalidArgumentError( | |
| absl::StrJoin(validation_tracker.GetFailureStatuses(), ";")); | |
| } | |
| return result.value(); | |
| } | |
| } // namespace credentio |