diff options
author | Ali Zhang <alizhang@google.com> | 2022-04-12 15:17:42 -0700 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-04-13 17:31:03 +0000 |
commit | 5e66df561dc1a1039dd77965f68051ddbef1023e (patch) | |
tree | 4809586871dcc85d9dbe09b11120cc0ab4aacc49 /pw_software_update/update_bundle_accessor.cc | |
parent | 9e7d4a4a0a1e7a341c4122d3ff473be7d23d0030 (diff) | |
download | pigweed-5e66df561dc1a1039dd77965f68051ddbef1023e.tar.gz |
pw_software_update: Make root rotation optional
While root metadata rotation is a great resilience mechanism, it does
come with non-zero cost and it is a downstream right to opt out.
Test: Manual OTA for all (rotation, self_verification) combinations.
Change-Id: I58687dcb1c8015d2027ad46eafe1c0fac61e8361
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/90945
Pigweed-Auto-Submit: Ali Zhang <alizhang@google.com>
Reviewed-by: Yecheng Zhao <zyecheng@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
Diffstat (limited to 'pw_software_update/update_bundle_accessor.cc')
-rw-r--r-- | pw_software_update/update_bundle_accessor.cc | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/pw_software_update/update_bundle_accessor.cc b/pw_software_update/update_bundle_accessor.cc index 453f932e8..2bab5d2b0 100644 --- a/pw_software_update/update_bundle_accessor.cc +++ b/pw_software_update/update_bundle_accessor.cc @@ -369,10 +369,25 @@ Status UpdateBundleAccessor::DoVerify() { #else // PW_SOFTWARE_UPDATE_DISABLE_BUNDLE_VERIFICATION bundle_verified_ = false; + if (self_verification_) { + // Use root metadata in staged bundle for self-verification. This root + // metadata is optional and used opportunistically in the rest of the + // verification flow. + trusted_root_ = bundle_.AsMessage( + static_cast<uint32_t>(UpdateBundle::Fields::ROOT_METADATA)); + } else { + // A provisioned on-device root metadata is *required* for formal + // verification. + if (trusted_root_ = GetOnDeviceTrustedRoot(); !trusted_root_.ok()) { + PW_LOG_CRITICAL("Missing on-device trusted root"); + return Status::Unauthenticated(); + } + } + // Verify and upgrade the on-device trust to the incoming root metadata if // one is included. if (Status status = UpgradeRoot(); !status.ok()) { - PW_LOG_ERROR("Failed to upgrade to Root in staged bundle"); + PW_LOG_ERROR("Failed to rotate root metadata"); return status; } @@ -429,25 +444,16 @@ ManifestAccessor UpdateBundleAccessor::GetOnDeviceManifest() { } Status UpdateBundleAccessor::UpgradeRoot() { +#if PW_SOFTWARE_UPDATE_WITH_ROOT_ROTATION protobuf::Message new_root = bundle_.AsMessage( static_cast<uint32_t>(UpdateBundle::Fields::ROOT_METADATA)); - // Try self-verification even if verification is disabled by the caller. This - // minimizes surprises when the caller do decide to turn on verification. - bool self_verifying = disable_verification_; - - // Choose and cache the root metadata to trust. - trusted_root_ = self_verifying ? new_root : GetOnDeviceTrustedRoot(); - if (!new_root.status().ok()) { // Don't bother upgrading if not found or invalid. - PW_LOG_WARN("Incoming root metadata not found or invalid"); + PW_LOG_WARN("Skipping root metadata rotation: not found or invalid"); return OkStatus(); } - // A valid trust anchor is required onwards from here. - PW_TRY(trusted_root_.status()); - // TODO(pwbug/456): Check whether the bundle contains a root metadata that // is different from the on-device trusted root. @@ -502,7 +508,7 @@ Status UpdateBundleAccessor::UpgradeRoot() { return Status::Unauthenticated(); } - if (!self_verifying) { + if (!self_verification_) { // Persist the root immediately after it is successfully verified. This is // to make sure the trust anchor is up-to-date in storage as soon as // we are confident. Although targets metadata and product-specific @@ -511,7 +517,11 @@ Status UpdateBundleAccessor::UpgradeRoot() { // compromise keys. stream::IntervalReader new_root_reader = new_root.ToBytes().GetBytesReader(); - PW_TRY(backend_.SafelyPersistRootMetadata(new_root_reader)); + if (Status status = backend_.SafelyPersistRootMetadata(new_root_reader); + !status.ok()) { + PW_LOG_ERROR("Failed to persist rotated root metadata"); + return status; + } } // TODO(pwbug/456): Implement key change detection to determine whether @@ -519,12 +529,14 @@ Status UpdateBundleAccessor::UpgradeRoot() { // if any of the targets keys has been rotated. return OkStatus(); +#else + // Root metadata rotation opted out. + return OkStatus(); +#endif // PW_SOFTWARE_UPDATE_WITH_ROOT_ROTATION } Status UpdateBundleAccessor::VerifyTargetsMetadata() { - bool self_verifying = disable_verification_; - - if (self_verifying && !trusted_root_.status().ok()) { + if (self_verification_ && !trusted_root_.status().ok()) { PW_LOG_WARN( "Self-verification won't verify Targets metadata because there is no " "root"); @@ -580,7 +592,7 @@ Status UpdateBundleAccessor::VerifyTargetsMetadata() { static_cast<uint32_t>(RootMetadata::Fields::KEYS)); PW_TRY(key_mapping.status()); - // Get the targest metadtata siganture requirement from the trusted root. + // Get the target metadtata signature requirement from the trusted root. protobuf::Message signature_requirement = trusted_root.AsMessage(static_cast<uint32_t>( RootMetadata::Fields::TARGETS_SIGNATURE_REQUIREMENT)); @@ -593,7 +605,7 @@ Status UpdateBundleAccessor::VerifyTargetsMetadata() { signature_requirement, key_mapping); - if (self_verifying && sig_res.IsNotFound()) { + if (self_verification_ && sig_res.IsNotFound()) { PW_LOG_WARN("Self-verification ignoring unsigned bundle"); return OkStatus(); } @@ -605,9 +617,9 @@ Status UpdateBundleAccessor::VerifyTargetsMetadata() { // TODO(pwbug/456): Check targets metadtata content. - if (self_verifying) { + if (self_verification_) { // Don't bother because it does not matter. - PW_LOG_WARN("Self verification does not do Targets metadata anti-rollback"); + PW_LOG_WARN("Self verification skips Targets metadata anti-rollback"); return OkStatus(); } |