| // 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 <cstdint> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/base/nullability.h" | |
| #include "absl/functional/any_invocable.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "async/async_context.h" | |
| #include "cose/sig_structure.h" | |
| #include "cose/timestamp_creator.h" | |
| #include "cppbor/cppbor.h" | |
| namespace credentio { | |
| void TimestampUpdater::UpdateTimestamp( | |
| std::string* absl_nonnull encoded_cose_sign1, AsyncContext async_context, | |
| absl::AnyInvocable<void(absl::Status) &&> cb) const { | |
| int64_t original_size = encoded_cose_sign1->size(); | |
| auto cose_sign1_or = DecodeCoseSign1TaggedStructure(*encoded_cose_sign1); | |
| if (!cose_sign1_or.ok()) { | |
| AsyncResolver<void>(async_context, std::move(cb)) | |
| .Return(cose_sign1_or.status()); | |
| return; | |
| } | |
| CoseSign1TaggedStructure cose_sign1 = *std::move(cose_sign1_or); | |
| absl::AnyInvocable<void(absl::StatusOr<std::string>) &&> done_cb = | |
| [cose_sign1 = cose_sign1, original_size, encoded_cose_sign1, | |
| async_context, cb = std::move(cb)]( | |
| absl::StatusOr<std::string> status_or_timestamp) mutable { | |
| AsyncResolver<void> resolver(async_context, std::move(cb)); | |
| if (!status_or_timestamp.ok()) { | |
| resolver.Return(status_or_timestamp.status()); | |
| return; | |
| } | |
| cose_sign1.unprotected_header = { | |
| .sig_tst2 = | |
| TstContainer{ | |
| .tst_tokens = {{.val = std::move(*status_or_timestamp)}}}, | |
| .pad = "", | |
| }; | |
| int64_t delta = | |
| original_size - EncodeCoseSign1TaggedStructure(cose_sign1).size(); | |
| if (delta < 0) { | |
| resolver.Return( | |
| absl::InvalidArgumentError("Not enough space for timestamp.")); | |
| return; | |
| } | |
| // Adjust padding to account for the encoded size of the `pad` field | |
| // (size zero is encoded with 1 byte). | |
| int64_t pad_size = delta - cppbor::Uint(delta).encodedSize() + 1; | |
| cose_sign1.unprotected_header.pad = std::string(pad_size, '\0'); | |
| *encoded_cose_sign1 = EncodeCoseSign1TaggedStructure(cose_sign1); | |
| if (encoded_cose_sign1->size() != original_size) { | |
| resolver.Return( | |
| absl::InternalError("wrong size after updating timestamp")); | |
| return; | |
| } | |
| resolver.Return(absl::OkStatus()); | |
| }; | |
| timestamp_creator_.CreateTimestamp( | |
| cose_sign1, TimestampCreator::Options{.async_context = async_context}, | |
| std::move(done_cb)); | |
| } | |
| } // namespace credentio |