pw_software_update: Use a user_manifest target file
Instead of embedding user metadata in the TargetsMetadata, a
reserved "user_manifest" target file is used to pass the user's
metadata as an opaque blob.
During verification this blob is handed to the backend to verify
when desired.
Requires: pigweed-internal:16500
Change-Id: I111d8cbbfb2a43b68baea0c4b0545e6005a0a9de
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/65361
Reviewed-by: David Rogers <davidrogers@google.com>
Commit-Queue: Ewout van Bekkum <ewout@google.com>
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
diff --git a/pw_software_update/bundled_update_service.cc b/pw_software_update/bundled_update_service.cc
index 1f2cb0b..1f8bcde 100644
--- a/pw_software_update/bundled_update_service.cc
+++ b/pw_software_update/bundled_update_service.cc
@@ -63,6 +63,12 @@
} while (false)
namespace pw::software_update {
+namespace {
+
+constexpr std::string_view kTopLevelTargetsName = "targets";
+constexpr std::string_view kUserManifestTargetFileName = "user_manifest";
+
+} // namespace
Status BundledUpdateService::GetStatus(
ServerContext&,
@@ -168,6 +174,19 @@
bundle_open_ = true;
}
+ // Have the backend verify the user_manifest if present.
+ stream::IntervalReader user_manifest =
+ bundle_.GetTargetPayload(kUserManifestTargetFileName);
+ if (user_manifest.ok()) {
+ const size_t bundle_offset = user_manifest.start();
+ if (!backend_.VerifyUserManifest(user_manifest, bundle_offset).ok()) {
+ std::lock_guard lock(mutex_);
+ SET_ERROR(pw_software_update_BundledUpdateResult_Enum_VERIFY_FAILED,
+ "Backend::VerifyUserManifest() failed");
+ return;
+ }
+ }
+
// Notify backend we're done verifying.
status = backend_.AfterBundleVerified();
{
@@ -323,7 +342,6 @@
// There should only be one element in the map, which is the top-level
// targets metadata.
- constexpr std::string_view kTopLevelTargetsName = "targets";
protobuf::Message signed_targets_metadata =
signed_targets_metadata_map[kTopLevelTargetsName];
if (const Status status = signed_targets_metadata.status(); !status.ok()) {
@@ -413,6 +431,9 @@
const std::string_view file_name_view(
reinterpret_cast<const char*>(file_name_span.data()),
file_name_span.size_bytes());
+ if (file_name_view.compare(kUserManifestTargetFileName) == 0) {
+ continue; // user_manifest is not applied by the backend.
+ }
stream::IntervalReader file_reader =
bundle_.GetTargetPayload(file_name_view);
const size_t bundle_offset = file_reader.start();
diff --git a/pw_software_update/public/pw_software_update/bundled_update_backend.h b/pw_software_update/public/pw_software_update/bundled_update_backend.h
index 9ead759..ba79d86 100644
--- a/pw_software_update/public/pw_software_update/bundled_update_backend.h
+++ b/pw_software_update/public/pw_software_update/bundled_update_backend.h
@@ -62,9 +62,11 @@
virtual Status BeforeBundleVerify() { return OkStatus(); };
// Perform any product-specific bundle verification tasks (e.g. hw version
- // match check), done after TUF bundle verification process.
- virtual Status VerifyMetadata(
- [[maybe_unused]] const ManifestAccessor& manifest) {
+ // match check), done after TUF bundle verification process if user_manifest
+ // was provided as part of the bundle.
+ virtual Status VerifyUserManifest(
+ [[maybe_unused]] stream::Reader& user_manifest,
+ [[maybe_unused]] size_t update_bundle_offset) {
return OkStatus();
};