DO NOT MERGE - qt-qpr1-dev-plus-aosp-without-vendor@5915889 into stage-aosp-master
Bug: 142003500
Change-Id: I1a417153e5ff0703d13591a8a074cd390c193877
diff --git a/Android.bp b/Android.bp
index 1be0d63..54fd0c2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -128,6 +128,7 @@
"libverity_tree",
],
shared_libs: [
+ "libziparchive",
"libbase",
"libcrypto",
"libfec",
@@ -164,6 +165,7 @@
"common/utils.cc",
"payload_consumer/bzip_extent_writer.cc",
"payload_consumer/cached_file_descriptor.cc",
+ "payload_consumer/certificate_parser_android.cc",
"payload_consumer/delta_performer.cc",
"payload_consumer/download_action.cc",
"payload_consumer/extent_reader.cc",
@@ -202,6 +204,7 @@
"liblp",
"libutils",
"android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
],
target: {
recovery: {
@@ -304,7 +307,7 @@
static_libs: ["libupdate_engine_android"],
required: [
"cacerts_google",
- "update_engine_payload_key",
+ "otacerts",
],
srcs: ["main.cc"],
@@ -378,7 +381,7 @@
},
required: [
- "update_engine_payload_key.recovery",
+ "otacerts.recovery",
],
}
@@ -598,16 +601,19 @@
name: "ue_unittest_keys",
cmd: "openssl rsa -in $(location unittest_key.pem) -pubout -out $(location unittest_key.pub.pem) &&" +
"openssl rsa -in $(location unittest_key2.pem) -pubout -out $(location unittest_key2.pub.pem) &&" +
- "openssl rsa -in $(location unittest_key_RSA4096.pem) -pubout -out $(location unittest_key_RSA4096.pub.pem)",
+ "openssl rsa -in $(location unittest_key_RSA4096.pem) -pubout -out $(location unittest_key_RSA4096.pub.pem) &&" +
+ "openssl pkey -in $(location unittest_key_EC.pem) -pubout -out $(location unittest_key_EC.pub.pem)",
srcs: [
"unittest_key.pem",
"unittest_key2.pem",
"unittest_key_RSA4096.pem",
+ "unittest_key_EC.pem",
],
out: [
"unittest_key.pub.pem",
"unittest_key2.pub.pem",
"unittest_key_RSA4096.pub.pem",
+ "unittest_key_EC.pub.pem",
],
}
@@ -656,9 +662,11 @@
":ue_unittest_delta_generator",
":ue_unittest_disk_imgs",
":ue_unittest_keys",
+ "otacerts.zip",
"unittest_key.pem",
"unittest_key2.pem",
"unittest_key_RSA4096.pem",
+ "unittest_key_EC.pem",
"update_engine.conf",
],
@@ -689,6 +697,7 @@
"dynamic_partition_control_android_unittest.cc",
"payload_consumer/bzip_extent_writer_unittest.cc",
"payload_consumer/cached_file_descriptor_unittest.cc",
+ "payload_consumer/certificate_parser_android_unittest.cc",
"payload_consumer/delta_performer_integration_test.cc",
"payload_consumer/delta_performer_unittest.cc",
"payload_consumer/extent_reader_unittest.cc",
diff --git a/binder_bindings/android/os/IUpdateEngine.aidl b/binder_bindings/android/os/IUpdateEngine.aidl
index cde05be..1305079 100644
--- a/binder_bindings/android/os/IUpdateEngine.aidl
+++ b/binder_bindings/android/os/IUpdateEngine.aidl
@@ -17,6 +17,7 @@
package android.os;
import android.os.IUpdateEngineCallback;
+import android.os.ParcelFileDescriptor;
/** @hide */
interface IUpdateEngine {
@@ -26,7 +27,7 @@
in long payload_size,
in String[] headerKeyValuePairs);
/** @hide */
- void applyPayloadFd(in FileDescriptor fd,
+ void applyPayloadFd(in ParcelFileDescriptor pfd,
in long payload_offset,
in long payload_size,
in String[] headerKeyValuePairs);
diff --git a/binder_service_android.cc b/binder_service_android.cc
index 1799438..88bc1f2 100644
--- a/binder_service_android.cc
+++ b/binder_service_android.cc
@@ -16,16 +16,15 @@
#include "update_engine/binder_service_android.h"
-#include <android-base/unique_fd.h>
#include <base/bind.h>
#include <base/logging.h>
#include <binderwrapper/binder_wrapper.h>
#include <brillo/errors/error.h>
#include <utils/String8.h>
-using android::base::unique_fd;
using android::binder::Status;
using android::os::IUpdateEngineCallback;
+using android::os::ParcelFileDescriptor;
using std::string;
using std::vector;
using update_engine::UpdateEngineStatus;
@@ -115,7 +114,7 @@
}
Status BinderUpdateEngineAndroidService::applyPayloadFd(
- const ::android::base::unique_fd& fd,
+ const ParcelFileDescriptor& pfd,
int64_t payload_offset,
int64_t payload_size,
const vector<android::String16>& header_kv_pairs) {
@@ -127,7 +126,7 @@
brillo::ErrorPtr error;
if (!service_delegate_->ApplyPayload(
- fd.get(), payload_offset, payload_size, str_headers, &error)) {
+ pfd.get(), payload_offset, payload_size, str_headers, &error)) {
return ErrorPtrToStatus(error);
}
return Status::ok();
diff --git a/binder_service_android.h b/binder_service_android.h
index ec4a93b..0dda93b 100644
--- a/binder_service_android.h
+++ b/binder_service_android.h
@@ -54,7 +54,7 @@
int64_t payload_size,
const std::vector<android::String16>& header_kv_pairs) override;
android::binder::Status applyPayloadFd(
- const ::android::base::unique_fd& fd,
+ const ::android::os::ParcelFileDescriptor& pfd,
int64_t payload_offset,
int64_t payload_size,
const std::vector<android::String16>& header_kv_pairs) override;
diff --git a/boot_control_android.cc b/boot_control_android.cc
index 4a010bd..b1d775e 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -308,12 +308,8 @@
return true;
}
- if (!update_metadata) {
- return true;
- }
-
return dynamic_control_->PreparePartitionsForUpdate(
- source_slot, target_slot, manifest);
+ source_slot, target_slot, manifest, update_metadata);
}
} // namespace chromeos_update_engine
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc
index f090de2..e44af15 100644
--- a/boot_control_android_unittest.cc
+++ b/boot_control_android_unittest.cc
@@ -197,6 +197,9 @@
{T("system"), 2_GiB},
{T("vendor"), 1_GiB}});
+ EXPECT_CALL(dynamicControl(), PreparePartitionsForUpdate(_, _, _, false))
+ .WillOnce(Return(true));
+
EXPECT_TRUE(PreparePartitionsForUpdate(
target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false));
diff --git a/common/platform_constants.h b/common/platform_constants.h
index 6eaa940..243af69 100644
--- a/common/platform_constants.h
+++ b/common/platform_constants.h
@@ -38,6 +38,10 @@
// whole payload.
extern const char kUpdatePayloadPublicKeyPath[];
+// Path to the location of the zip archive file that contains PEM encoded X509
+// certificates. e.g. 'system/etc/security/otacerts.zip'.
+extern const char kUpdateCertificatesPath[];
+
// Path to the directory containing all the SSL certificates accepted by
// update_engine when sending requests to Omaha and the download server (if
// HTTPS is used for that as well).
diff --git a/common/platform_constants_android.cc b/common/platform_constants_android.cc
index 9d8d30e..f468c3b 100644
--- a/common/platform_constants_android.cc
+++ b/common/platform_constants_android.cc
@@ -25,8 +25,8 @@
"https://clients2.google.com/service/update2/brillo";
const char kOmahaUpdaterID[] = "Brillo";
const char kOmahaPlatformName[] = "Brillo";
-const char kUpdatePayloadPublicKeyPath[] =
- "/etc/update_engine/update-payload-key.pub.pem";
+const char kUpdatePayloadPublicKeyPath[] = "";
+const char kUpdateCertificatesPath[] = "/system/etc/security/otacerts.zip";
const char kCACertificatesPath[] = "/system/etc/security/cacerts_google";
// No deadline file API support on Android.
const char kOmahaResponseDeadlineFile[] = "";
diff --git a/common/platform_constants_chromeos.cc b/common/platform_constants_chromeos.cc
index f1ac490..fe94a45 100644
--- a/common/platform_constants_chromeos.cc
+++ b/common/platform_constants_chromeos.cc
@@ -27,6 +27,7 @@
const char kOmahaPlatformName[] = "Chrome OS";
const char kUpdatePayloadPublicKeyPath[] =
"/usr/share/update_engine/update-payload-key.pub.pem";
+const char kUpdateCertificatesPath[] = "";
const char kCACertificatesPath[] = "/usr/share/chromeos-ca-certificates";
const char kOmahaResponseDeadlineFile[] = "/tmp/update-check-response-deadline";
// This directory is wiped during powerwash.
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc
index 8dcf343..e194670 100644
--- a/dynamic_partition_control_android.cc
+++ b/dynamic_partition_control_android.cc
@@ -62,13 +62,6 @@
// needs to be mapped, this timeout is longer than |kMapTimeout|.
constexpr std::chrono::milliseconds kMapSnapshotTimeout{5000};
-DynamicPartitionControlAndroid::DynamicPartitionControlAndroid() {
- if (GetVirtualAbFeatureFlag().IsEnabled()) {
- snapshot_ = android::snapshot::SnapshotManager::New();
- CHECK(snapshot_ != nullptr) << "Cannot initialize SnapshotManager.";
- }
-}
-
DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() {
CleanupInternal(false /* wait */);
}
@@ -91,12 +84,22 @@
return FeatureFlag(FeatureFlag::Value::NONE);
}
+DynamicPartitionControlAndroid::DynamicPartitionControlAndroid()
+ : dynamic_partitions_(
+ GetFeatureFlag(kUseDynamicPartitions, kRetrfoitDynamicPartitions)),
+ virtual_ab_(GetFeatureFlag(kVirtualAbEnabled, kVirtualAbRetrofit)) {
+ if (GetVirtualAbFeatureFlag().IsEnabled()) {
+ snapshot_ = android::snapshot::SnapshotManager::New();
+ CHECK(snapshot_ != nullptr) << "Cannot initialize SnapshotManager.";
+ }
+}
+
FeatureFlag DynamicPartitionControlAndroid::GetDynamicPartitionsFeatureFlag() {
- return GetFeatureFlag(kUseDynamicPartitions, kRetrfoitDynamicPartitions);
+ return dynamic_partitions_;
}
FeatureFlag DynamicPartitionControlAndroid::GetVirtualAbFeatureFlag() {
- return GetFeatureFlag(kVirtualAbEnabled, kVirtualAbRetrofit);
+ return virtual_ab_;
}
bool DynamicPartitionControlAndroid::MapPartitionInternal(
@@ -112,7 +115,8 @@
.force_writable = force_writable,
};
bool success = false;
- if (GetVirtualAbFeatureFlag().IsEnabled() && force_writable) {
+ if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_ &&
+ force_writable) {
// Only target partitions are mapped with force_writable. On Virtual
// A/B devices, target partitions may overlap with source partitions, so
// they must be mapped with snapshot.
@@ -256,8 +260,12 @@
builder =
MetadataBuilder::New(PartitionOpener(), super_device, source_slot);
} else {
- builder = MetadataBuilder::NewForUpdate(
- PartitionOpener(), super_device, source_slot, target_slot);
+ bool always_keep_source_slot = !target_supports_snapshot_;
+ builder = MetadataBuilder::NewForUpdate(PartitionOpener(),
+ super_device,
+ source_slot,
+ target_slot,
+ always_keep_source_slot);
}
if (builder == nullptr) {
@@ -343,13 +351,35 @@
bool DynamicPartitionControlAndroid::PreparePartitionsForUpdate(
uint32_t source_slot,
uint32_t target_slot,
- const DeltaArchiveManifest& manifest) {
- // TODO(elsk): Also call PrepareDynamicPartitionsForUpdate when applying
- // downgrade packages on retrofit Virtual A/B devices and when applying
- // secondary OTA. b/138258570
+ const DeltaArchiveManifest& manifest,
+ bool update) {
+ target_supports_snapshot_ =
+ manifest.dynamic_partition_metadata().snapshot_enabled();
+
+ if (!update)
+ return true;
+
if (GetVirtualAbFeatureFlag().IsEnabled()) {
- return PrepareSnapshotPartitionsForUpdate(
- source_slot, target_slot, manifest);
+ // On Virtual A/B device, either CancelUpdate() or BeginUpdate() must be
+ // called before calling UnmapUpdateSnapshot.
+ // - If target_supports_snapshot_, PrepareSnapshotPartitionsForUpdate()
+ // calls BeginUpdate() which resets update state
+ // - If !target_supports_snapshot_, explicitly CancelUpdate().
+ if (target_supports_snapshot_) {
+ return PrepareSnapshotPartitionsForUpdate(
+ source_slot, target_slot, manifest);
+ }
+
+ if (GetVirtualAbFeatureFlag().IsLaunch() && !target_supports_snapshot_) {
+ LOG(ERROR) << "Cannot downgrade to a build that does not support "
+ << "snapshots because this device launches with Virtual A/B.";
+ return false;
+ }
+
+ if (!snapshot_->CancelUpdate()) {
+ LOG(ERROR) << "Cannot cancel previous update.";
+ return false;
+ }
}
return PrepareDynamicPartitionsForUpdate(source_slot, target_slot, manifest);
}
@@ -418,6 +448,11 @@
MetadataBuilder* builder,
uint32_t target_slot,
const DeltaArchiveManifest& manifest) {
+ // If applying downgrade from Virtual A/B to non-Virtual A/B, the left-over
+ // COW group needs to be deleted to ensure there are enough space to create
+ // target partitions.
+ builder->RemoveGroupAndPartitions(android::snapshot::kCowGroupName);
+
const std::string target_suffix = SlotSuffixForSlotNumber(target_slot);
DeleteGroupsWithSuffix(builder, target_suffix);
@@ -491,10 +526,11 @@
}
bool DynamicPartitionControlAndroid::FinishUpdate() {
- if (!GetVirtualAbFeatureFlag().IsEnabled())
- return true;
- LOG(INFO) << "Snapshot writes are done.";
- return snapshot_->FinishedSnapshotWrites();
+ if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_) {
+ LOG(INFO) << "Snapshot writes are done.";
+ return snapshot_->FinishedSnapshotWrites();
+ }
+ return true;
}
} // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h
index f9dfd89..d70a2aa 100644
--- a/dynamic_partition_control_android.h
+++ b/dynamic_partition_control_android.h
@@ -46,10 +46,10 @@
std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
const std::string& super_device, uint32_t source_slot) override;
- bool PreparePartitionsForUpdate(
- uint32_t source_slot,
- uint32_t target_slot,
- const DeltaArchiveManifest& manifest) override;
+ bool PreparePartitionsForUpdate(uint32_t source_slot,
+ uint32_t target_slot,
+ const DeltaArchiveManifest& manifest,
+ bool update) override;
bool GetDeviceDir(std::string* path) override;
std::string GetSuperPartitionName(uint32_t slot) override;
bool FinishUpdate() override;
@@ -112,7 +112,10 @@
const DeltaArchiveManifest& manifest);
std::set<std::string> mapped_devices_;
+ const FeatureFlag dynamic_partitions_;
+ const FeatureFlag virtual_ab_;
std::unique_ptr<android::snapshot::SnapshotManager> snapshot_;
+ bool target_supports_snapshot_ = false;
DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid);
};
diff --git a/dynamic_partition_control_android_unittest.cc b/dynamic_partition_control_android_unittest.cc
index 552774e..e8ef1f9 100644
--- a/dynamic_partition_control_android_unittest.cc
+++ b/dynamic_partition_control_android_unittest.cc
@@ -112,7 +112,7 @@
}
bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
return dynamicControl().PreparePartitionsForUpdate(
- source(), target(), PartitionSizesToManifest(partition_sizes));
+ source(), target(), PartitionSizesToManifest(partition_sizes), true);
}
void SetSlots(const TestParam& slots) { slots_ = slots; }
diff --git a/dynamic_partition_control_interface.h b/dynamic_partition_control_interface.h
index 0ccfcd6..9c18973 100644
--- a/dynamic_partition_control_interface.h
+++ b/dynamic_partition_control_interface.h
@@ -36,6 +36,7 @@
constexpr explicit FeatureFlag(Value value) : value_(value) {}
constexpr bool IsEnabled() const { return value_ != Value::NONE; }
constexpr bool IsRetrofit() const { return value_ == Value::RETROFIT; }
+ constexpr bool IsLaunch() const { return value_ == Value::LAUNCH; }
private:
Value value_;
@@ -92,10 +93,11 @@
// Prepare all partitions for an update specified in |manifest|.
// This is needed before calling MapPartitionOnDeviceMapper(), otherwise the
// device would be mapped in an inconsistent way.
- virtual bool PreparePartitionsForUpdate(
- uint32_t source_slot,
- uint32_t target_slot,
- const DeltaArchiveManifest& manifest) = 0;
+ // If |update| is set, create snapshots and writes super partition metadata.
+ virtual bool PreparePartitionsForUpdate(uint32_t source_slot,
+ uint32_t target_slot,
+ const DeltaArchiveManifest& manifest,
+ bool update) = 0;
// Return a possible location for devices listed by name.
virtual bool GetDeviceDir(std::string* path) = 0;
diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h
index 1af6cfe..8146e0f 100644
--- a/mock_dynamic_partition_control.h
+++ b/mock_dynamic_partition_control.h
@@ -44,8 +44,8 @@
const std::string&, uint32_t));
MOCK_METHOD1(GetDeviceDir, bool(std::string*));
MOCK_METHOD0(GetDynamicPartitionsFeatureFlag, FeatureFlag());
- MOCK_METHOD3(PreparePartitionsForUpdate,
- bool(uint32_t, uint32_t, const DeltaArchiveManifest&));
+ MOCK_METHOD4(PreparePartitionsForUpdate,
+ bool(uint32_t, uint32_t, const DeltaArchiveManifest&, bool));
MOCK_METHOD1(GetSuperPartitionName, std::string(uint32_t));
MOCK_METHOD0(GetVirtualAbFeatureFlag, FeatureFlag());
MOCK_METHOD0(FinishUpdate, bool());
diff --git a/otacerts.zip b/otacerts.zip
new file mode 100644
index 0000000..00a5a51
--- /dev/null
+++ b/otacerts.zip
Binary files differ
diff --git a/payload_consumer/certificate_parser_android.cc b/payload_consumer/certificate_parser_android.cc
new file mode 100644
index 0000000..4a20547
--- /dev/null
+++ b/payload_consumer/certificate_parser_android.cc
@@ -0,0 +1,121 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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
+//
+// http://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 "update_engine/payload_consumer/certificate_parser_android.h"
+
+#include <memory>
+#include <utility>
+
+#include <base/logging.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <ziparchive/zip_archive.h>
+
+#include "update_engine/payload_consumer/certificate_parser_interface.h"
+
+namespace {
+bool IterateZipEntriesAndSearchForKeys(
+ const ZipArchiveHandle& handle, std::vector<std::vector<uint8_t>>* result) {
+ void* cookie;
+ int32_t iter_status = StartIteration(handle, &cookie, "", "x509.pem");
+ if (iter_status != 0) {
+ LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: "
+ << ErrorCodeString(iter_status);
+ return false;
+ }
+ std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
+
+ std::vector<std::vector<uint8_t>> pem_keys;
+ std::string_view name;
+ ZipEntry entry;
+ while ((iter_status = Next(cookie, &entry, &name)) == 0) {
+ std::vector<uint8_t> pem_content(entry.uncompressed_length);
+ if (int32_t extract_status = ExtractToMemory(
+ handle, &entry, pem_content.data(), pem_content.size());
+ extract_status != 0) {
+ LOG(ERROR) << "Failed to extract " << name << ": "
+ << ErrorCodeString(extract_status);
+ return false;
+ }
+ pem_keys.push_back(pem_content);
+ }
+
+ if (iter_status != -1) {
+ LOG(ERROR) << "Error while iterating over zip entries: "
+ << ErrorCodeString(iter_status);
+ return false;
+ }
+
+ *result = std::move(pem_keys);
+ return true;
+}
+
+} // namespace
+
+namespace chromeos_update_engine {
+bool CertificateParserAndroid::ReadPublicKeysFromCertificates(
+ const std::string& path,
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
+ out_public_keys) {
+ out_public_keys->clear();
+
+ ZipArchiveHandle handle;
+ if (int32_t open_status = OpenArchive(path.c_str(), &handle);
+ open_status != 0) {
+ LOG(ERROR) << "Failed to open " << path << ": "
+ << ErrorCodeString(open_status);
+ return false;
+ }
+
+ std::vector<std::vector<uint8_t>> pem_certs;
+ if (!IterateZipEntriesAndSearchForKeys(handle, &pem_certs)) {
+ CloseArchive(handle);
+ return false;
+ }
+ CloseArchive(handle);
+
+ // Convert the certificates into public keys. Stop and return false if we
+ // encounter an error.
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> result;
+ for (const auto& cert : pem_certs) {
+ std::unique_ptr<BIO, decltype(&BIO_free)> input(
+ BIO_new_mem_buf(cert.data(), cert.size()), BIO_free);
+
+ std::unique_ptr<X509, decltype(&X509_free)> x509(
+ PEM_read_bio_X509(input.get(), nullptr, nullptr, nullptr), X509_free);
+ if (!x509) {
+ LOG(ERROR) << "Failed to read x509 certificate";
+ return false;
+ }
+
+ std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> public_key(
+ X509_get_pubkey(x509.get()), EVP_PKEY_free);
+ if (!public_key) {
+ LOG(ERROR) << "Failed to extract the public key from x509 certificate";
+ return false;
+ }
+ result.push_back(std::move(public_key));
+ }
+
+ *out_public_keys = std::move(result);
+ return true;
+}
+
+std::unique_ptr<CertificateParserInterface> CreateCertificateParser() {
+ return std::make_unique<CertificateParserAndroid>();
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_android.h b/payload_consumer/certificate_parser_android.h
new file mode 100644
index 0000000..ccb9293
--- /dev/null
+++ b/payload_consumer/certificate_parser_android.h
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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
+//
+// http://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.
+//
+
+#ifndef UPDATE_ENGINE_CERTIFICATE_PARSER_ANDROID_H_
+#define UPDATE_ENGINE_CERTIFICATE_PARSER_ANDROID_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "payload_consumer/certificate_parser_interface.h"
+
+namespace chromeos_update_engine {
+// This class parses the certificates from a zip file. Because the Android
+// build system stores the certs in otacerts.zip.
+class CertificateParserAndroid : public CertificateParserInterface {
+ public:
+ CertificateParserAndroid() = default;
+
+ bool ReadPublicKeysFromCertificates(
+ const std::string& path,
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
+ out_public_keys) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CertificateParserAndroid);
+};
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/certificate_parser_android_unittest.cc b/payload_consumer/certificate_parser_android_unittest.cc
new file mode 100644
index 0000000..e300414
--- /dev/null
+++ b/payload_consumer/certificate_parser_android_unittest.cc
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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
+//
+// http://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 "update_engine/payload_consumer/certificate_parser_interface.h"
+
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/payload_verifier.h"
+#include "update_engine/payload_generator/payload_signer.h"
+
+namespace chromeos_update_engine {
+
+extern const char* kUnittestPrivateKeyPath;
+const char* kUnittestOtacertsPath = "otacerts.zip";
+
+TEST(CertificateParserAndroidTest, ParseZipArchive) {
+ std::string ota_cert =
+ test_utils::GetBuildArtifactsPath(kUnittestOtacertsPath);
+ ASSERT_TRUE(utils::FileExists(ota_cert.c_str()));
+
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> keys;
+ auto parser = CreateCertificateParser();
+ ASSERT_TRUE(parser->ReadPublicKeysFromCertificates(ota_cert, &keys));
+ ASSERT_EQ(1u, keys.size());
+}
+
+TEST(CertificateParserAndroidTest, VerifySignature) {
+ brillo::Blob hash_blob;
+ ASSERT_TRUE(HashCalculator::RawHashOfData({'x'}, &hash_blob));
+ brillo::Blob sig_blob;
+ ASSERT_TRUE(PayloadSigner::SignHash(
+ hash_blob,
+ test_utils::GetBuildArtifactsPath(kUnittestPrivateKeyPath),
+ &sig_blob));
+
+ auto verifier = PayloadVerifier::CreateInstanceFromZipPath(
+ test_utils::GetBuildArtifactsPath(kUnittestOtacertsPath));
+ ASSERT_TRUE(verifier != nullptr);
+ ASSERT_TRUE(verifier->VerifyRawSignature(sig_blob, hash_blob, nullptr));
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_interface.h b/payload_consumer/certificate_parser_interface.h
new file mode 100644
index 0000000..dad23d2
--- /dev/null
+++ b/payload_consumer/certificate_parser_interface.h
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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
+//
+// http://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.
+//
+
+#ifndef UPDATE_ENGINE_CERTIFICATE_PARSER_INTERFACE_H_
+#define UPDATE_ENGINE_CERTIFICATE_PARSER_INTERFACE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <openssl/pem.h>
+
+namespace chromeos_update_engine {
+
+// This class parses the PEM encoded X509 certificates from |path|; and
+// passes the parsed public keys to the caller.
+class CertificateParserInterface {
+ public:
+ virtual ~CertificateParserInterface() = default;
+
+ virtual bool ReadPublicKeysFromCertificates(
+ const std::string& path,
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
+ out_public_keys) = 0;
+};
+
+std::unique_ptr<CertificateParserInterface> CreateCertificateParser();
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/certificate_parser_stub.cc b/payload_consumer/certificate_parser_stub.cc
new file mode 100644
index 0000000..95fd6e8
--- /dev/null
+++ b/payload_consumer/certificate_parser_stub.cc
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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
+//
+// http://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 <payload_consumer/certificate_parser_stub.h>
+
+namespace chromeos_update_engine {
+bool CertificateParserStub::ReadPublicKeysFromCertificates(
+ const std::string& path,
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
+ out_public_keys) {
+ return true;
+}
+
+std::unique_ptr<CertificateParserInterface> CreateCertificateParser() {
+ return std::make_unique<CertificateParserStub>();
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_stub.h b/payload_consumer/certificate_parser_stub.h
new file mode 100644
index 0000000..f4f8825
--- /dev/null
+++ b/payload_consumer/certificate_parser_stub.h
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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
+//
+// http://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.
+//
+
+#ifndef UPDATE_ENGINE_CERTIFICATE_PARSER_STUB_H_
+#define UPDATE_ENGINE_CERTIFICATE_PARSER_STUB_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "payload_consumer/certificate_parser_interface.h"
+
+namespace chromeos_update_engine {
+class CertificateParserStub : public CertificateParserInterface {
+ public:
+ CertificateParserStub() = default;
+
+ bool ReadPublicKeysFromCertificates(
+ const std::string& path,
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
+ out_public_keys) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CertificateParserStub);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_CERTIFICATE_PARSER_STUB_H_
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 3ff98ca..4aec00b 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -46,6 +46,7 @@
#include "update_engine/common/terminator.h"
#include "update_engine/payload_consumer/bzip_extent_writer.h"
#include "update_engine/payload_consumer/cached_file_descriptor.h"
+#include "update_engine/payload_consumer/certificate_parser_interface.h"
#include "update_engine/payload_consumer/download_action.h"
#include "update_engine/payload_consumer/extent_reader.h"
#include "update_engine/payload_consumer/extent_writer.h"
@@ -526,17 +527,19 @@
<< "Trusting metadata size in payload = " << metadata_size_;
}
- string public_key;
- if (!GetPublicKey(&public_key)) {
- LOG(ERROR) << "Failed to get public key.";
+ auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
+ if (!payload_verifier) {
+ LOG(ERROR) << "Failed to create payload verifier.";
*error = ErrorCode::kDownloadMetadataSignatureVerificationError;
- return MetadataParseResult::kError;
+ if (perform_verification) {
+ return MetadataParseResult::kError;
+ }
+ } else {
+ // We have the full metadata in |payload|. Verify its integrity
+ // and authenticity based on the information we have in Omaha response.
+ *error = payload_metadata_.ValidateMetadataSignature(
+ payload, payload_->metadata_signature, *payload_verifier);
}
-
- // We have the full metadata in |payload|. Verify its integrity
- // and authenticity based on the information we have in Omaha response.
- *error = payload_metadata_.ValidateMetadataSignature(
- payload, payload_->metadata_signature, public_key);
if (*error != ErrorCode::kSuccess) {
if (install_plan_->hash_checks_mandatory) {
// The autoupdate_CatchBadSignatures test checks for this string
@@ -1596,10 +1599,32 @@
return brillo::data_encoding::Base64Decode(install_plan_->public_key_rsa,
out_public_key);
}
-
+ LOG(INFO) << "No public keys found for verification.";
return true;
}
+std::pair<std::unique_ptr<PayloadVerifier>, bool>
+DeltaPerformer::CreatePayloadVerifier() {
+ if (utils::FileExists(update_certificates_path_.c_str())) {
+ LOG(INFO) << "Verifying using certificates: " << update_certificates_path_;
+ return {
+ PayloadVerifier::CreateInstanceFromZipPath(update_certificates_path_),
+ true};
+ }
+
+ string public_key;
+ if (!GetPublicKey(&public_key)) {
+ LOG(ERROR) << "Failed to read public key";
+ return {nullptr, true};
+ }
+
+ // Skips the verification if the public key is empty.
+ if (public_key.empty()) {
+ return {nullptr, false};
+ }
+ return {PayloadVerifier::CreateInstance(public_key), true};
+}
+
ErrorCode DeltaPerformer::ValidateManifest() {
// Perform assorted checks to sanity check the manifest, make sure it
// matches data from other sources, and that it is a supported version.
@@ -1760,12 +1785,6 @@
ErrorCode DeltaPerformer::VerifyPayload(
const brillo::Blob& update_check_response_hash,
const uint64_t update_check_response_size) {
- string public_key;
- if (!GetPublicKey(&public_key)) {
- LOG(ERROR) << "Failed to get public key.";
- return ErrorCode::kDownloadPayloadPubKeyVerificationError;
- }
-
// Verifies the download size.
if (update_check_response_size !=
metadata_size_ + metadata_signature_size_ + buffer_offset_) {
@@ -1783,19 +1802,22 @@
ErrorCode::kPayloadHashMismatchError,
payload_hash_calculator_.raw_hash() == update_check_response_hash);
- // Verifies the signed payload hash.
- if (public_key.empty()) {
- LOG(WARNING) << "Not verifying signed delta payload -- missing public key.";
- return ErrorCode::kSuccess;
- }
TEST_AND_RETURN_VAL(ErrorCode::kSignedDeltaPayloadExpectedError,
!signatures_message_data_.empty());
brillo::Blob hash_data = signed_hash_calculator_.raw_hash();
TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
hash_data.size() == kSHA256Size);
- if (!PayloadVerifier::VerifySignature(
- signatures_message_data_, public_key, hash_data)) {
+ auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
+ if (!perform_verification) {
+ LOG(WARNING) << "Not verifying signed delta payload -- missing public key.";
+ return ErrorCode::kSuccess;
+ }
+ if (!payload_verifier) {
+ LOG(ERROR) << "Failed to create the payload verifier.";
+ return ErrorCode::kDownloadPayloadPubKeyVerificationError;
+ }
+ if (!payload_verifier->VerifySignature(signatures_message_data_, hash_data)) {
// The autoupdate_CatchBadSignatures test checks for this string
// in log-files. Keep in sync.
LOG(ERROR) << "Public key verification failed, thus update failed.";
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index 25c348c..4c64dfa 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -20,7 +20,9 @@
#include <inttypes.h>
#include <limits>
+#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include <base/time/time.h>
@@ -34,6 +36,7 @@
#include "update_engine/payload_consumer/file_writer.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/payload_metadata.h"
+#include "update_engine/payload_consumer/payload_verifier.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
@@ -156,6 +159,11 @@
public_key_path_ = public_key_path;
}
+ void set_update_certificates_path(
+ const std::string& update_certificates_path) {
+ update_certificates_path_ = update_certificates_path;
+ }
+
// Return true if header parsing is finished and no errors occurred.
bool IsHeaderParsed() const;
@@ -273,6 +281,12 @@
// |out_public_key|. Returns false on failures.
bool GetPublicKey(std::string* out_public_key);
+ // Creates a PayloadVerifier from the zip file containing certificates. If the
+ // path to the zip file doesn't exist, falls back to use the public key.
+ // Returns a tuple with the created PayloadVerifier and if we should perform
+ // the verification.
+ std::pair<std::unique_ptr<PayloadVerifier>, bool> CreatePayloadVerifier();
+
// After install_plan_ is filled with partition names and sizes, initialize
// metadata of partitions and map necessary devices before opening devices.
bool PreparePartitionsForUpdate();
@@ -383,6 +397,9 @@
// override with test keys.
std::string public_key_path_{constants::kUpdatePayloadPublicKeyPath};
+ // The path to the zip file with X509 certificates.
+ std::string update_certificates_path_{constants::kUpdateCertificatesPath};
+
// The number of bytes received so far, used for progress tracking.
size_t total_bytes_received_{0};
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index 38494f2..a2ad77b 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -60,6 +60,8 @@
extern const char* kUnittestPublicKeyPath;
extern const char* kUnittestPrivateKey2Path;
extern const char* kUnittestPublicKey2Path;
+extern const char* kUnittestPrivateKeyECPath;
+extern const char* kUnittestPublicKeyECPath;
static const uint32_t kDefaultKernelSize = 4096; // Something small for a test
// clang-format off
@@ -107,6 +109,7 @@
kSignatureGeneratedPlaceholder, // Insert placeholder signatures, then real.
kSignatureGeneratedPlaceholderMismatch, // Insert a wrong sized placeholder.
kSignatureGeneratedShell, // Sign the generated payload through shell cmds.
+ kSignatureGeneratedShellECKey, // Sign with a EC key through shell cmds.
kSignatureGeneratedShellBadKey, // Sign with a bad key through shell cmds.
kSignatureGeneratedShellRotateCl1, // Rotate key, test client v1
kSignatureGeneratedShellRotateCl2, // Rotate key, test client v2
@@ -164,53 +167,127 @@
return true;
}
-static size_t GetSignatureSize(const string& private_key_path) {
- const brillo::Blob data(1, 'x');
- brillo::Blob hash;
- EXPECT_TRUE(HashCalculator::RawHashOfData(data, &hash));
- brillo::Blob signature;
- EXPECT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
- return signature.size();
-}
-
static bool InsertSignaturePlaceholder(size_t signature_size,
const string& payload_path,
uint64_t* out_metadata_size) {
vector<brillo::Blob> signatures;
signatures.push_back(brillo::Blob(signature_size, 0));
- return PayloadSigner::AddSignatureToPayload(
- payload_path, signatures, {}, payload_path, out_metadata_size);
+ return PayloadSigner::AddSignatureToPayload(payload_path,
+ {signature_size},
+ signatures,
+ {},
+ payload_path,
+ out_metadata_size);
}
static void SignGeneratedPayload(const string& payload_path,
uint64_t* out_metadata_size) {
string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
- size_t signature_size = GetSignatureSize(private_key_path);
+ size_t signature_size;
+ ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(private_key_path,
+ &signature_size));
brillo::Blob hash;
ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
payload_path, {signature_size}, &hash, nullptr));
brillo::Blob signature;
ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
- ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(
- payload_path, {signature}, {}, payload_path, out_metadata_size));
+ ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(payload_path,
+ {signature_size},
+ {signature},
+ {},
+ payload_path,
+ out_metadata_size));
EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
}
+static void SignGeneratedShellPayloadWithKeys(
+ const string& payload_path,
+ const vector<string>& private_key_paths,
+ const string& public_key_path,
+ bool verification_success) {
+ vector<string> signature_size_strings;
+ for (const auto& key_path : private_key_paths) {
+ size_t signature_size;
+ ASSERT_TRUE(
+ PayloadSigner::GetMaximumSignatureSize(key_path, &signature_size));
+ signature_size_strings.push_back(base::StringPrintf("%zu", signature_size));
+ }
+ string signature_size_string = base::JoinString(signature_size_strings, ":");
+
+ test_utils::ScopedTempFile hash_file("hash.XXXXXX");
+ string delta_generator_path = GetBuildArtifactsPath("delta_generator");
+ ASSERT_EQ(0,
+ System(base::StringPrintf(
+ "%s -in_file=%s -signature_size=%s -out_hash_file=%s",
+ delta_generator_path.c_str(),
+ payload_path.c_str(),
+ signature_size_string.c_str(),
+ hash_file.path().c_str())));
+
+ // Sign the hash with all private keys.
+ vector<test_utils::ScopedTempFile> sig_files;
+ vector<string> sig_file_paths;
+ for (const auto& key_path : private_key_paths) {
+ brillo::Blob hash, signature;
+ ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
+ ASSERT_TRUE(PayloadSigner::SignHash(hash, key_path, &signature));
+
+ test_utils::ScopedTempFile sig_file("signature.XXXXXX");
+ ASSERT_TRUE(test_utils::WriteFileVector(sig_file.path(), signature));
+ sig_file_paths.push_back(sig_file.path());
+ sig_files.push_back(std::move(sig_file));
+ }
+ string sig_files_string = base::JoinString(sig_file_paths, ":");
+
+ // Add the signature to the payload.
+ ASSERT_EQ(0,
+ System(base::StringPrintf("%s --signature_size=%s -in_file=%s "
+ "-payload_signature_file=%s -out_file=%s",
+ delta_generator_path.c_str(),
+ signature_size_string.c_str(),
+ payload_path.c_str(),
+ sig_files_string.c_str(),
+ payload_path.c_str())));
+
+ int verify_result = System(base::StringPrintf("%s -in_file=%s -public_key=%s",
+ delta_generator_path.c_str(),
+ payload_path.c_str(),
+ public_key_path.c_str()));
+
+ if (verification_success) {
+ ASSERT_EQ(0, verify_result);
+ } else {
+ ASSERT_NE(0, verify_result);
+ }
+}
+
static void SignGeneratedShellPayload(SignatureTest signature_test,
const string& payload_path) {
- string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
+ vector<SignatureTest> supported_test = {
+ kSignatureGeneratedShell,
+ kSignatureGeneratedShellBadKey,
+ kSignatureGeneratedShellECKey,
+ kSignatureGeneratedShellRotateCl1,
+ kSignatureGeneratedShellRotateCl2,
+ };
+ ASSERT_TRUE(std::find(supported_test.begin(),
+ supported_test.end(),
+ signature_test) != supported_test.end());
+
+ string private_key_path;
if (signature_test == kSignatureGeneratedShellBadKey) {
ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX", &private_key_path, nullptr));
+ } else if (signature_test == kSignatureGeneratedShellECKey) {
+ private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyECPath);
} else {
- ASSERT_TRUE(signature_test == kSignatureGeneratedShell ||
- signature_test == kSignatureGeneratedShellRotateCl1 ||
- signature_test == kSignatureGeneratedShellRotateCl2);
+ private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
}
ScopedPathUnlinker key_unlinker(private_key_path);
key_unlinker.set_should_remove(signature_test ==
kSignatureGeneratedShellBadKey);
+
// Generates a new private key that will not match the public key.
if (signature_test == kSignatureGeneratedShellBadKey) {
LOG(INFO) << "Generating a mismatched private key.";
@@ -229,64 +306,26 @@
fclose(fprikey);
RSA_free(rsa);
}
- size_t signature_size = GetSignatureSize(private_key_path);
- test_utils::ScopedTempFile hash_file("hash.XXXXXX");
- string signature_size_string;
- if (signature_test == kSignatureGeneratedShellRotateCl1 ||
- signature_test == kSignatureGeneratedShellRotateCl2)
- signature_size_string =
- base::StringPrintf("%zu:%zu", signature_size, signature_size);
- else
- signature_size_string = base::StringPrintf("%zu", signature_size);
- string delta_generator_path = GetBuildArtifactsPath("delta_generator");
- ASSERT_EQ(0,
- System(base::StringPrintf(
- "%s -in_file=%s -signature_size=%s -out_hash_file=%s",
- delta_generator_path.c_str(),
- payload_path.c_str(),
- signature_size_string.c_str(),
- hash_file.path().c_str())));
- // Sign the hash
- brillo::Blob hash, signature;
- ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
- ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
-
- test_utils::ScopedTempFile sig_file("signature.XXXXXX");
- ASSERT_TRUE(test_utils::WriteFileVector(sig_file.path(), signature));
- string sig_files = sig_file.path();
-
- test_utils::ScopedTempFile sig_file2("signature.XXXXXX");
+ vector<string> private_key_paths = {private_key_path};
if (signature_test == kSignatureGeneratedShellRotateCl1 ||
signature_test == kSignatureGeneratedShellRotateCl2) {
- ASSERT_TRUE(PayloadSigner::SignHash(
- hash, GetBuildArtifactsPath(kUnittestPrivateKey2Path), &signature));
- ASSERT_TRUE(test_utils::WriteFileVector(sig_file2.path(), signature));
- // Append second sig file to first path
- sig_files += ":" + sig_file2.path();
+ private_key_paths.push_back(
+ GetBuildArtifactsPath(kUnittestPrivateKey2Path));
}
- ASSERT_EQ(0,
- System(base::StringPrintf(
- "%s -in_file=%s -payload_signature_file=%s -out_file=%s",
- delta_generator_path.c_str(),
- payload_path.c_str(),
- sig_files.c_str(),
- payload_path.c_str())));
- int verify_result = System(base::StringPrintf(
- "%s -in_file=%s -public_key=%s -public_key_version=%d",
- delta_generator_path.c_str(),
- payload_path.c_str(),
- (signature_test == kSignatureGeneratedShellRotateCl2
- ? GetBuildArtifactsPath(kUnittestPublicKey2Path)
- : GetBuildArtifactsPath(kUnittestPublicKeyPath))
- .c_str(),
- signature_test == kSignatureGeneratedShellRotateCl2 ? 2 : 1));
- if (signature_test == kSignatureGeneratedShellBadKey) {
- ASSERT_NE(0, verify_result);
+ std::string public_key;
+ if (signature_test == kSignatureGeneratedShellRotateCl2) {
+ public_key = GetBuildArtifactsPath(kUnittestPublicKey2Path);
+ } else if (signature_test == kSignatureGeneratedShellECKey) {
+ public_key = GetBuildArtifactsPath(kUnittestPublicKeyECPath);
} else {
- ASSERT_EQ(0, verify_result);
+ public_key = GetBuildArtifactsPath(kUnittestPublicKeyPath);
}
+
+ bool verification_success = signature_test != kSignatureGeneratedShellBadKey;
+ SignGeneratedShellPayloadWithKeys(
+ payload_path, private_key_paths, public_key, verification_success);
}
static void GenerateDeltaFile(bool full_kernel,
@@ -531,8 +570,9 @@
if (signature_test == kSignatureGeneratedPlaceholder ||
signature_test == kSignatureGeneratedPlaceholderMismatch) {
- size_t signature_size =
- GetSignatureSize(GetBuildArtifactsPath(kUnittestPrivateKeyPath));
+ size_t signature_size;
+ ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(
+ GetBuildArtifactsPath(kUnittestPrivateKeyPath), &signature_size));
LOG(INFO) << "Inserting placeholder signature.";
ASSERT_TRUE(InsertSignaturePlaceholder(
signature_size, state->delta_path, &state->metadata_size));
@@ -555,6 +595,7 @@
LOG(INFO) << "Signing payload.";
SignGeneratedPayload(state->delta_path, &state->metadata_size);
} else if (signature_test == kSignatureGeneratedShell ||
+ signature_test == kSignatureGeneratedShellECKey ||
signature_test == kSignatureGeneratedShellBadKey ||
signature_test == kSignatureGeneratedShellRotateCl1 ||
signature_test == kSignatureGeneratedShellRotateCl2) {
@@ -597,14 +638,15 @@
else
EXPECT_EQ(1, sigs_message.signatures_size());
const Signatures::Signature& signature = sigs_message.signatures(0);
- EXPECT_EQ(1U, signature.version());
- uint64_t expected_sig_data_length = 0;
vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
- if (signature_test == kSignatureGeneratedShellRotateCl1 ||
- signature_test == kSignatureGeneratedShellRotateCl2) {
+ if (signature_test == kSignatureGeneratedShellECKey) {
+ key_paths = {GetBuildArtifactsPath(kUnittestPrivateKeyECPath)};
+ } else if (signature_test == kSignatureGeneratedShellRotateCl1 ||
+ signature_test == kSignatureGeneratedShellRotateCl2) {
key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
}
+ uint64_t expected_sig_data_length = 0;
EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
key_paths, &expected_sig_data_length));
EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
@@ -717,7 +759,9 @@
ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
state->delta.data(),
state->metadata_size,
- GetBuildArtifactsPath(kUnittestPrivateKeyPath),
+ (signature_test == kSignatureGeneratedShellECKey)
+ ? GetBuildArtifactsPath(kUnittestPrivateKeyECPath)
+ : GetBuildArtifactsPath(kUnittestPrivateKeyPath),
&install_plan->payloads[0].metadata_signature));
EXPECT_FALSE(install_plan->payloads[0].metadata_signature.empty());
@@ -728,9 +772,12 @@
install_plan,
&install_plan->payloads[0],
false /* interactive */);
- string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
+ string public_key_path = signature_test == kSignatureGeneratedShellECKey
+ ? GetBuildArtifactsPath(kUnittestPublicKeyECPath)
+ : GetBuildArtifactsPath(kUnittestPublicKeyPath);
EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
(*performer)->set_public_key_path(public_key_path);
+ (*performer)->set_update_certificates_path("");
EXPECT_EQ(static_cast<off_t>(state->image_size),
HashCalculator::RawHashOfFile(
@@ -1060,6 +1107,17 @@
}
TEST(DeltaPerformerIntegrationTest,
+ RunAsRootSmallImageSignGeneratedShellECKeyTest) {
+ DoSmallImageTest(false,
+ false,
+ false,
+ -1,
+ kSignatureGeneratedShellECKey,
+ false,
+ kInPlaceMinorPayloadVersion);
+}
+
+TEST(DeltaPerformerIntegrationTest,
RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
DoSmallImageTest(false,
false,
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index b7a38cc..e9022ba 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -159,6 +159,11 @@
install_plan_.target_slot = 1;
EXPECT_CALL(mock_delegate_, ShouldCancel(_))
.WillRepeatedly(testing::Return(false));
+ performer_.set_update_certificates_path("");
+ // Set the public key corresponding to the unittest private key.
+ string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
+ EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
+ performer_.set_public_key_path(public_key_path);
}
// Test helper placed where it can easily be friended from DeltaPerformer.
@@ -388,12 +393,6 @@
expected_error = ErrorCode::kSuccess;
}
- // Use the public key corresponding to the private key used above to
- // sign the metadata.
- string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
- EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
- performer_.set_public_key_path(public_key_path);
-
// Init actual_error with an invalid value so that we make sure
// ParsePayloadMetadata properly populates it in all cases.
actual_error = ErrorCode::kUmaReportedMax;
@@ -920,7 +919,6 @@
brillo::Blob payload_data = GeneratePayload(
{}, {}, true, kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion);
install_plan_.hash_checks_mandatory = true;
- performer_.set_public_key_path(GetBuildArtifactsPath(kUnittestPublicKeyPath));
ErrorCode error;
EXPECT_EQ(MetadataParseResult::kSuccess,
performer_.ParsePayloadMetadata(payload_data, &error));
diff --git a/payload_consumer/payload_metadata.cc b/payload_consumer/payload_metadata.cc
index 3739767..0952646 100644
--- a/payload_consumer/payload_metadata.cc
+++ b/payload_consumer/payload_metadata.cc
@@ -159,7 +159,7 @@
ErrorCode PayloadMetadata::ValidateMetadataSignature(
const brillo::Blob& payload,
const string& metadata_signature,
- const string& pem_public_key) const {
+ const PayloadVerifier& payload_verifier) const {
if (payload.size() < metadata_size_ + metadata_signature_size_)
return ErrorCode::kDownloadMetadataSignatureError;
@@ -202,31 +202,18 @@
}
if (!metadata_signature_blob.empty()) {
- brillo::Blob expected_metadata_hash;
- if (!PayloadVerifier::GetRawHashFromSignature(
- metadata_signature_blob, pem_public_key, &expected_metadata_hash)) {
- LOG(ERROR) << "Unable to compute expected hash from metadata signature";
- return ErrorCode::kDownloadMetadataSignatureError;
- }
-
- brillo::Blob padded_metadata_hash = metadata_hash;
- if (!PayloadVerifier::PadRSASHA256Hash(&padded_metadata_hash,
- expected_metadata_hash.size())) {
- LOG(ERROR) << "Failed to pad the SHA256 hash to "
- << expected_metadata_hash.size() << " bytes.";
- return ErrorCode::kDownloadMetadataSignatureVerificationError;
- }
-
- if (padded_metadata_hash != expected_metadata_hash) {
- LOG(ERROR) << "Manifest hash verification failed. Expected hash = ";
- utils::HexDumpVector(expected_metadata_hash);
- LOG(ERROR) << "Calculated hash = ";
- utils::HexDumpVector(padded_metadata_hash);
+ brillo::Blob decrypted_signature;
+ if (!payload_verifier.VerifyRawSignature(
+ metadata_signature_blob, metadata_hash, &decrypted_signature)) {
+ LOG(ERROR) << "Manifest hash verification failed. Decrypted hash = ";
+ utils::HexDumpVector(decrypted_signature);
+ LOG(ERROR) << "Calculated hash before padding = ";
+ utils::HexDumpVector(metadata_hash);
return ErrorCode::kDownloadMetadataSignatureMismatch;
}
} else {
- if (!PayloadVerifier::VerifySignature(
- metadata_signature_protobuf, pem_public_key, metadata_hash)) {
+ if (!payload_verifier.VerifySignature(metadata_signature_protobuf,
+ metadata_hash)) {
LOG(ERROR) << "Manifest hash verification failed.";
return ErrorCode::kDownloadMetadataSignatureMismatch;
}
diff --git a/payload_consumer/payload_metadata.h b/payload_consumer/payload_metadata.h
index 1b4c5c8..75ef8f9 100644
--- a/payload_consumer/payload_metadata.h
+++ b/payload_consumer/payload_metadata.h
@@ -27,6 +27,7 @@
#include "update_engine/common/error_code.h"
#include "update_engine/common/platform_constants.h"
+#include "update_engine/payload_consumer/payload_verifier.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
@@ -65,9 +66,10 @@
// metadata is parsed so that a man-in-the-middle attack on the SSL connection
// to the payload server doesn't exploit any vulnerability in the code that
// parses the protocol buffer.
- ErrorCode ValidateMetadataSignature(const brillo::Blob& payload,
- const std::string& metadata_signature,
- const std::string& pem_public_key) const;
+ ErrorCode ValidateMetadataSignature(
+ const brillo::Blob& payload,
+ const std::string& metadata_signature,
+ const PayloadVerifier& payload_verifier) const;
// Returns the major payload version. If the version was not yet parsed,
// returns zero.
diff --git a/payload_consumer/payload_verifier.cc b/payload_consumer/payload_verifier.cc
index 3a3ccbf..24e337e 100644
--- a/payload_consumer/payload_verifier.cc
+++ b/payload_consumer/payload_verifier.cc
@@ -25,6 +25,7 @@
#include "update_engine/common/constants.h"
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/certificate_parser_interface.h"
#include "update_engine/update_metadata.pb.h"
using std::string;
@@ -51,9 +52,52 @@
} // namespace
-bool PayloadVerifier::VerifySignature(const string& signature_proto,
- const string& pem_public_key,
- const brillo::Blob& sha256_hash_data) {
+std::unique_ptr<PayloadVerifier> PayloadVerifier::CreateInstance(
+ const std::string& pem_public_key) {
+ std::unique_ptr<BIO, decltype(&BIO_free)> bp(
+ BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size()), BIO_free);
+ if (!bp) {
+ LOG(ERROR) << "Failed to read " << pem_public_key << " into buffer.";
+ return nullptr;
+ }
+
+ auto pub_key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>(
+ PEM_read_bio_PUBKEY(bp.get(), nullptr, nullptr, nullptr), EVP_PKEY_free);
+ if (!pub_key) {
+ LOG(ERROR) << "Failed to parse the public key in: " << pem_public_key;
+ return nullptr;
+ }
+
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> keys;
+ keys.emplace_back(std::move(pub_key));
+ return std::unique_ptr<PayloadVerifier>(new PayloadVerifier(std::move(keys)));
+}
+
+std::unique_ptr<PayloadVerifier> PayloadVerifier::CreateInstanceFromZipPath(
+ const std::string& certificate_zip_path) {
+ auto parser = CreateCertificateParser();
+ if (!parser) {
+ LOG(ERROR) << "Failed to create certificate parser from "
+ << certificate_zip_path;
+ return nullptr;
+ }
+
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> public_keys;
+ if (!parser->ReadPublicKeysFromCertificates(certificate_zip_path,
+ &public_keys) ||
+ public_keys.empty()) {
+ LOG(ERROR) << "Failed to parse public keys in: " << certificate_zip_path;
+ return nullptr;
+ }
+
+ return std::unique_ptr<PayloadVerifier>(
+ new PayloadVerifier(std::move(public_keys)));
+}
+
+bool PayloadVerifier::VerifySignature(
+ const string& signature_proto, const brillo::Blob& sha256_hash_data) const {
+ TEST_AND_RETURN_FALSE(!public_keys_.empty());
+
Signatures signatures;
LOG(INFO) << "signature blob size = " << signature_proto.size();
TEST_AND_RETURN_FALSE(signatures.ParseFromString(signature_proto));
@@ -67,48 +111,104 @@
// Tries every signature in the signature blob.
for (int i = 0; i < signatures.signatures_size(); i++) {
const Signatures::Signature& signature = signatures.signatures(i);
- brillo::Blob sig_data(signature.data().begin(), signature.data().end());
- brillo::Blob sig_hash_data;
- if (!GetRawHashFromSignature(sig_data, pem_public_key, &sig_hash_data))
- continue;
+ brillo::Blob sig_data;
+ if (signature.has_unpadded_signature_size()) {
+ TEST_AND_RETURN_FALSE(signature.unpadded_signature_size() <=
+ signature.data().size());
+ LOG(INFO) << "Truncating the signature to its unpadded size: "
+ << signature.unpadded_signature_size() << ".";
+ sig_data.assign(
+ signature.data().begin(),
+ signature.data().begin() + signature.unpadded_signature_size());
+ } else {
+ sig_data.assign(signature.data().begin(), signature.data().end());
+ }
- brillo::Blob padded_hash_data = sha256_hash_data;
- if (PadRSASHA256Hash(&padded_hash_data, sig_hash_data.size()) &&
- padded_hash_data == sig_hash_data) {
+ brillo::Blob sig_hash_data;
+ if (VerifyRawSignature(sig_data, sha256_hash_data, &sig_hash_data)) {
LOG(INFO) << "Verified correct signature " << i + 1 << " out of "
<< signatures.signatures_size() << " signatures.";
return true;
}
- tested_hashes.push_back(sig_hash_data);
+ if (!sig_hash_data.empty()) {
+ tested_hashes.push_back(sig_hash_data);
+ }
}
LOG(ERROR) << "None of the " << signatures.signatures_size()
<< " signatures is correct. Expected hash before padding:";
utils::HexDumpVector(sha256_hash_data);
- LOG(ERROR) << "But found decrypted hashes:";
+ LOG(ERROR) << "But found RSA decrypted hashes:";
for (const auto& sig_hash_data : tested_hashes) {
utils::HexDumpVector(sig_hash_data);
}
return false;
}
-bool PayloadVerifier::GetRawHashFromSignature(const brillo::Blob& sig_data,
- const string& pem_public_key,
- brillo::Blob* out_hash_data) {
+bool PayloadVerifier::VerifyRawSignature(
+ const brillo::Blob& sig_data,
+ const brillo::Blob& sha256_hash_data,
+ brillo::Blob* decrypted_sig_data) const {
+ TEST_AND_RETURN_FALSE(!public_keys_.empty());
+
+ for (const auto& public_key : public_keys_) {
+ int key_type = EVP_PKEY_id(public_key.get());
+ if (key_type == EVP_PKEY_RSA) {
+ brillo::Blob sig_hash_data;
+ if (!GetRawHashFromSignature(
+ sig_data, public_key.get(), &sig_hash_data)) {
+ LOG(WARNING)
+ << "Failed to get the raw hash with RSA key. Trying other keys.";
+ continue;
+ }
+
+ if (decrypted_sig_data != nullptr) {
+ *decrypted_sig_data = sig_hash_data;
+ }
+
+ brillo::Blob padded_hash_data = sha256_hash_data;
+ TEST_AND_RETURN_FALSE(
+ PadRSASHA256Hash(&padded_hash_data, sig_hash_data.size()));
+
+ if (padded_hash_data == sig_hash_data) {
+ return true;
+ }
+ }
+
+ if (key_type == EVP_PKEY_EC) {
+ EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(public_key.get());
+ TEST_AND_RETURN_FALSE(ec_key != nullptr);
+ if (ECDSA_verify(0,
+ sha256_hash_data.data(),
+ sha256_hash_data.size(),
+ sig_data.data(),
+ sig_data.size(),
+ ec_key) == 1) {
+ return true;
+ }
+ }
+
+ LOG(ERROR) << "Unsupported key type " << key_type;
+ return false;
+ }
+ LOG(INFO) << "Failed to verify the signature with " << public_keys_.size()
+ << " keys.";
+ return false;
+}
+
+bool PayloadVerifier::GetRawHashFromSignature(
+ const brillo::Blob& sig_data,
+ const EVP_PKEY* public_key,
+ brillo::Blob* out_hash_data) const {
// The code below executes the equivalent of:
//
- // openssl rsautl -verify -pubin -inkey <(echo |pem_public_key|)
+ // openssl rsautl -verify -pubin -inkey <(echo pem_public_key)
// -in |sig_data| -out |out_hash_data|
-
- BIO* bp = BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size());
- char dummy_password[] = {' ', 0}; // Ensure no password is read from stdin.
- RSA* rsa = PEM_read_bio_RSA_PUBKEY(bp, nullptr, nullptr, dummy_password);
- BIO_free(bp);
+ RSA* rsa = EVP_PKEY_get0_RSA(public_key);
TEST_AND_RETURN_FALSE(rsa != nullptr);
unsigned int keysize = RSA_size(rsa);
if (sig_data.size() > 2 * keysize) {
LOG(ERROR) << "Signature size is too big for public key size.";
- RSA_free(rsa);
return false;
}
@@ -116,7 +216,6 @@
brillo::Blob hash_data(keysize);
int decrypt_size = RSA_public_decrypt(
sig_data.size(), sig_data.data(), hash_data.data(), rsa, RSA_NO_PADDING);
- RSA_free(rsa);
TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
decrypt_size <= static_cast<int>(hash_data.size()));
hash_data.resize(decrypt_size);
diff --git a/payload_consumer/payload_verifier.h b/payload_consumer/payload_verifier.h
index af8e05f..bc5231f 100644
--- a/payload_consumer/payload_verifier.h
+++ b/payload_consumer/payload_verifier.h
@@ -17,38 +17,24 @@
#ifndef UPDATE_ENGINE_PAYLOAD_CONSUMER_PAYLOAD_VERIFIER_H_
#define UPDATE_ENGINE_PAYLOAD_CONSUMER_PAYLOAD_VERIFIER_H_
+#include <memory>
#include <string>
+#include <utility>
+#include <vector>
-#include <base/macros.h>
#include <brillo/secure_blob.h>
+#include <openssl/evp.h>
#include "update_engine/update_metadata.pb.h"
-// This class encapsulates methods used for payload signature verification.
-// See payload_generator/payload_signer.h for payload signing.
+// This class holds the public keys and implements methods used for payload
+// signature verification. See payload_generator/payload_signer.h for payload
+// signing.
namespace chromeos_update_engine {
class PayloadVerifier {
public:
- // Interprets |signature_proto| as a protocol buffer containing the Signatures
- // message and decrypts each signature data using the |pem_public_key|.
- // |pem_public_key| should be a PEM format RSA public key data.
- // Pads the 32 bytes |sha256_hash_data| to 256 or 512 bytes according to the
- // PKCS#1 v1.5 standard; and returns whether *any* of the decrypted hashes
- // matches the padded hash data. In case of any error parsing the signatures
- // or the public key, returns false.
- static bool VerifySignature(const std::string& signature_proto,
- const std::string& pem_public_key,
- const brillo::Blob& sha256_hash_data);
-
- // Decrypts |sig_data| with the given |pem_public_key| and populates
- // |out_hash_data| with the decoded raw hash. |pem_public_key| should be a PEM
- // format RSA public key data. Returns true if successful, false otherwise.
- static bool GetRawHashFromSignature(const brillo::Blob& sig_data,
- const std::string& pem_public_key,
- brillo::Blob* out_hash_data);
-
// Pads a SHA256 hash so that it may be encrypted/signed with RSA2048 or
// RSA4096 using the PKCS#1 v1.5 scheme.
// hash should be a pointer to vector of exactly 256 bits. |rsa_size| must be
@@ -57,9 +43,46 @@
// Returns true on success, false otherwise.
static bool PadRSASHA256Hash(brillo::Blob* hash, size_t rsa_size);
+ // Parses the input as a PEM encoded public string. And creates a
+ // PayloadVerifier with that public key for signature verification.
+ static std::unique_ptr<PayloadVerifier> CreateInstance(
+ const std::string& pem_public_key);
+
+ // Extracts the public keys from the certificates contained in the input
+ // zip file. And creates a PayloadVerifier with these public keys.
+ static std::unique_ptr<PayloadVerifier> CreateInstanceFromZipPath(
+ const std::string& certificate_zip_path);
+
+ // Interprets |signature_proto| as a protocol buffer containing the
+ // |Signatures| message and decrypts each signature data using the stored
+ // public key. Pads the 32 bytes |sha256_hash_data| to 256 or 512 bytes
+ // according to the PKCS#1 v1.5 standard; and returns whether *any* of the
+ // decrypted hashes matches the padded hash data. In case of any error parsing
+ // the signatures, returns false.
+ bool VerifySignature(const std::string& signature_proto,
+ const brillo::Blob& sha256_hash_data) const;
+
+ // Verifies if |sig_data| is a raw signature of the hash |sha256_hash_data|.
+ // If PayloadVerifier is using RSA as the public key, further puts the
+ // decrypted data of |sig_data| into |decrypted_sig_data|.
+ bool VerifyRawSignature(const brillo::Blob& sig_data,
+ const brillo::Blob& sha256_hash_data,
+ brillo::Blob* decrypted_sig_data) const;
+
private:
- // This should never be constructed
- DISALLOW_IMPLICIT_CONSTRUCTORS(PayloadVerifier);
+ explicit PayloadVerifier(
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>&&
+ public_keys)
+ : public_keys_(std::move(public_keys)) {}
+
+ // Decrypts |sig_data| with the given |public_key| and populates
+ // |out_hash_data| with the decoded raw hash. Returns true if successful,
+ // false otherwise.
+ bool GetRawHashFromSignature(const brillo::Blob& sig_data,
+ const EVP_PKEY* public_key,
+ brillo::Blob* out_hash_data) const;
+
+ std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> public_keys_;
};
} // namespace chromeos_update_engine
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index bef09bb..f035ff1 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -63,9 +63,6 @@
bool parsing_successful = base::StringToSizeT(str, &size);
LOG_IF(FATAL, !parsing_successful) << "Invalid signature size: " << str;
- LOG_IF(FATAL, size != 256 && size != 512)
- << "Only signature sizes of 256 or 512 bytes are supported.";
-
signature_sizes->push_back(size);
}
}
@@ -138,6 +135,7 @@
void SignPayload(const string& in_file,
const string& out_file,
+ const vector<size_t>& signature_sizes,
const string& payload_signature_file,
const string& metadata_signature_file,
const string& out_metadata_size_file) {
@@ -151,6 +149,7 @@
SignatureFileFlagToBlobs(metadata_signature_file, &metadata_signatures);
uint64_t final_metadata_size;
CHECK(PayloadSigner::AddSignatureToPayload(in_file,
+ signature_sizes,
payload_signatures,
metadata_signatures,
out_file,
@@ -424,6 +423,10 @@
DEFINE_bool(disable_fec_computation,
false,
"Disables the fec data computation on device.");
+ DEFINE_string(
+ out_maximum_signature_size_file,
+ "",
+ "Path to the output maximum signature size given a private key.");
brillo::FlagHelper::Init(
argc,
@@ -445,6 +448,30 @@
// Initialize the Xz compressor.
XzCompressInit();
+ if (!FLAGS_out_maximum_signature_size_file.empty()) {
+ LOG_IF(FATAL, FLAGS_private_key.empty())
+ << "Private key is not provided when calculating the maximum signature "
+ "size.";
+
+ size_t maximum_signature_size;
+ if (!PayloadSigner::GetMaximumSignatureSize(FLAGS_private_key,
+ &maximum_signature_size)) {
+ LOG(ERROR) << "Failed to get the maximum signature size of private key: "
+ << FLAGS_private_key;
+ return 1;
+ }
+ // Write the size string to output file.
+ string signature_size_string = std::to_string(maximum_signature_size);
+ if (!utils::WriteFile(FLAGS_out_maximum_signature_size_file.c_str(),
+ signature_size_string.c_str(),
+ signature_size_string.size())) {
+ PLOG(ERROR) << "Failed to write the maximum signature size to "
+ << FLAGS_out_maximum_signature_size_file << ".";
+ return 1;
+ }
+ return 0;
+ }
+
vector<size_t> signature_sizes;
if (!FLAGS_signature_size.empty()) {
ParseSignatureSizes(FLAGS_signature_size, &signature_sizes);
@@ -461,6 +488,7 @@
if (!FLAGS_payload_signature_file.empty()) {
SignPayload(FLAGS_in_file,
FLAGS_out_file,
+ signature_sizes,
FLAGS_payload_signature_file,
FLAGS_metadata_signature_file,
FLAGS_out_metadata_size_file);
diff --git a/payload_generator/payload_signer.cc b/payload_generator/payload_signer.cc
index 9739052..72780b1 100644
--- a/payload_generator/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -18,6 +18,7 @@
#include <endian.h>
+#include <memory>
#include <utility>
#include <base/logging.h>
@@ -46,23 +47,29 @@
namespace chromeos_update_engine {
namespace {
-
-// The payload verifier will check all the signatures included in the payload
-// regardless of the version field. Old version of the verifier require the
-// version field to be included and be 1.
-const uint32_t kSignatureMessageLegacyVersion = 1;
-
// Given raw |signatures|, packs them into a protobuf and serializes it into a
// string. Returns true on success, false otherwise.
bool ConvertSignaturesToProtobuf(const vector<brillo::Blob>& signatures,
+ const vector<size_t>& padded_signature_sizes,
string* out_serialized_signature) {
+ TEST_AND_RETURN_FALSE(signatures.size() == padded_signature_sizes.size());
// Pack it into a protobuf
Signatures out_message;
- for (const brillo::Blob& signature : signatures) {
+ for (size_t i = 0; i < signatures.size(); i++) {
+ const auto& signature = signatures[i];
+ const auto& padded_signature_size = padded_signature_sizes[i];
+ TEST_AND_RETURN_FALSE(padded_signature_size >= signature.size());
Signatures::Signature* sig_message = out_message.add_signatures();
- // Set all the signatures with the same version number.
- sig_message->set_version(kSignatureMessageLegacyVersion);
- sig_message->set_data(signature.data(), signature.size());
+ // Skip assigning the same version number because we don't need to be
+ // compatible with old major version 1 client anymore.
+
+ // TODO(Xunchang) don't need to set the unpadded_signature_size field for
+ // RSA key signed signatures.
+ sig_message->set_unpadded_signature_size(signature.size());
+ brillo::Blob padded_signature = signature;
+ padded_signature.insert(
+ padded_signature.end(), padded_signature_size - signature.size(), 0);
+ sig_message->set_data(padded_signature.data(), padded_signature.size());
}
// Serialize protobuf
@@ -203,8 +210,35 @@
return true;
}
+std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> CreatePrivateKeyFromPath(
+ const string& private_key_path) {
+ FILE* fprikey = fopen(private_key_path.c_str(), "rb");
+ if (!fprikey) {
+ PLOG(ERROR) << "Failed to read " << private_key_path;
+ return {nullptr, nullptr};
+ }
+
+ auto private_key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>(
+ PEM_read_PrivateKey(fprikey, nullptr, nullptr, nullptr), EVP_PKEY_free);
+ fclose(fprikey);
+ return private_key;
+}
+
} // namespace
+bool PayloadSigner::GetMaximumSignatureSize(const string& private_key_path,
+ size_t* signature_size) {
+ *signature_size = 0;
+ auto private_key = CreatePrivateKeyFromPath(private_key_path);
+ if (!private_key) {
+ LOG(ERROR) << "Failed to create private key from " << private_key_path;
+ return false;
+ }
+
+ *signature_size = EVP_PKEY_size(private_key.get());
+ return true;
+}
+
void PayloadSigner::AddSignatureToManifest(uint64_t signature_blob_offset,
uint64_t signature_blob_length,
bool add_dummy_op,
@@ -255,14 +289,18 @@
string public_key;
TEST_AND_RETURN_FALSE(utils::ReadFile(public_key_path, &public_key));
TEST_AND_RETURN_FALSE(payload_hash.size() == kSHA256Size);
+
+ auto payload_verifier = PayloadVerifier::CreateInstance(public_key);
+ TEST_AND_RETURN_FALSE(payload_verifier != nullptr);
+
TEST_AND_RETURN_FALSE(
- PayloadVerifier::VerifySignature(signature, public_key, payload_hash));
+ payload_verifier->VerifySignature(signature, payload_hash));
if (metadata_signature_size) {
signature.assign(payload.begin() + metadata_size,
payload.begin() + metadata_size + metadata_signature_size);
TEST_AND_RETURN_FALSE(metadata_hash.size() == kSHA256Size);
TEST_AND_RETURN_FALSE(
- PayloadVerifier::VerifySignature(signature, public_key, metadata_hash));
+ payload_verifier->VerifySignature(signature, metadata_hash));
}
return true;
}
@@ -278,29 +316,61 @@
// openssl rsautl -raw -sign -inkey |private_key_path|
// -in |padded_hash| -out |out_signature|
- FILE* fprikey = fopen(private_key_path.c_str(), "rb");
- TEST_AND_RETURN_FALSE(fprikey != nullptr);
- RSA* rsa = PEM_read_RSAPrivateKey(fprikey, nullptr, nullptr, nullptr);
- fclose(fprikey);
- TEST_AND_RETURN_FALSE(rsa != nullptr);
-
- brillo::Blob padded_hash = hash;
- PayloadVerifier::PadRSASHA256Hash(&padded_hash, RSA_size(rsa));
-
- brillo::Blob signature(RSA_size(rsa));
- ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
- padded_hash.data(),
- signature.data(),
- rsa,
- RSA_NO_PADDING);
- RSA_free(rsa);
- if (signature_size < 0) {
- LOG(ERROR) << "Signing hash failed: "
- << ERR_error_string(ERR_get_error(), nullptr);
+ auto private_key = CreatePrivateKeyFromPath(private_key_path);
+ if (!private_key) {
+ LOG(ERROR) << "Failed to create private key from " << private_key_path;
return false;
}
- TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
- signature.size());
+
+ int key_type = EVP_PKEY_id(private_key.get());
+ brillo::Blob signature;
+ if (key_type == EVP_PKEY_RSA) {
+ RSA* rsa = EVP_PKEY_get0_RSA(private_key.get());
+ TEST_AND_RETURN_FALSE(rsa != nullptr);
+
+ brillo::Blob padded_hash = hash;
+ PayloadVerifier::PadRSASHA256Hash(&padded_hash, RSA_size(rsa));
+
+ signature.resize(RSA_size(rsa));
+ ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
+ padded_hash.data(),
+ signature.data(),
+ rsa,
+ RSA_NO_PADDING);
+
+ if (signature_size < 0) {
+ LOG(ERROR) << "Signing hash failed: "
+ << ERR_error_string(ERR_get_error(), nullptr);
+ return false;
+ }
+ TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
+ signature.size());
+ } else if (key_type == EVP_PKEY_EC) {
+ EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(private_key.get());
+ TEST_AND_RETURN_FALSE(ec_key != nullptr);
+
+ signature.resize(ECDSA_size(ec_key));
+ unsigned int signature_size;
+ if (ECDSA_sign(0,
+ hash.data(),
+ hash.size(),
+ signature.data(),
+ &signature_size,
+ ec_key) != 1) {
+ LOG(ERROR) << "Signing hash failed: "
+ << ERR_error_string(ERR_get_error(), nullptr);
+ return false;
+ }
+
+ // NIST P-256
+ LOG(ERROR) << "signature max size " << signature.size() << " size "
+ << signature_size;
+ TEST_AND_RETURN_FALSE(signature.size() >= signature_size);
+ signature.resize(signature_size);
+ } else {
+ LOG(ERROR) << "key_type " << key_type << " isn't supported for signing";
+ return false;
+ }
out_signature->swap(signature);
return true;
}
@@ -309,13 +379,19 @@
const vector<string>& private_key_paths,
string* out_serialized_signature) {
vector<brillo::Blob> signatures;
+ vector<size_t> padded_signature_sizes;
for (const string& path : private_key_paths) {
brillo::Blob signature;
TEST_AND_RETURN_FALSE(SignHash(hash_data, path, &signature));
signatures.push_back(signature);
+
+ size_t padded_signature_size;
+ TEST_AND_RETURN_FALSE(
+ GetMaximumSignatureSize(path, &padded_signature_size));
+ padded_signature_sizes.push_back(padded_signature_size);
}
- TEST_AND_RETURN_FALSE(
- ConvertSignaturesToProtobuf(signatures, out_serialized_signature));
+ TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(
+ signatures, padded_signature_sizes, out_serialized_signature));
return true;
}
@@ -362,7 +438,8 @@
signatures.emplace_back(signature_size, 0);
}
string signature;
- TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(signatures, &signature));
+ TEST_AND_RETURN_FALSE(
+ ConvertSignaturesToProtobuf(signatures, signature_sizes, &signature));
brillo::Blob payload;
uint64_t metadata_size, signatures_offset;
@@ -386,6 +463,7 @@
bool PayloadSigner::AddSignatureToPayload(
const string& payload_path,
+ const vector<size_t>& padded_signature_sizes,
const vector<brillo::Blob>& payload_signatures,
const vector<brillo::Blob>& metadata_signatures,
const string& signed_payload_path,
@@ -394,11 +472,11 @@
// Loads the payload and adds the signature op to it.
string payload_signature, metadata_signature;
- TEST_AND_RETURN_FALSE(
- ConvertSignaturesToProtobuf(payload_signatures, &payload_signature));
+ TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(
+ payload_signatures, padded_signature_sizes, &payload_signature));
if (!metadata_signatures.empty()) {
- TEST_AND_RETURN_FALSE(
- ConvertSignaturesToProtobuf(metadata_signatures, &metadata_signature));
+ TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(
+ metadata_signatures, padded_signature_sizes, &metadata_signature));
}
brillo::Blob payload;
uint64_t signatures_offset;
diff --git a/payload_generator/payload_signer.h b/payload_generator/payload_signer.h
index 76e583b..bd1e32f 100644
--- a/payload_generator/payload_signer.h
+++ b/payload_generator/payload_signer.h
@@ -105,6 +105,7 @@
// otherwise.
static bool AddSignatureToPayload(
const std::string& payload_path,
+ const std::vector<size_t>& padded_signature_sizes,
const std::vector<brillo::Blob>& payload_signatures,
const std::vector<brillo::Blob>& metadata_signatures,
const std::string& signed_payload_path,
@@ -122,6 +123,13 @@
static bool ExtractPayloadProperties(const std::string& payload_path,
brillo::KeyValueStore* properties);
+ // This function calculates the maximum size, in bytes, of a signature signed
+ // by private_key_path. For an RSA key, this returns the number of bytes
+ // needed to represent the modulus. For an EC key, this returns the maximum
+ // size of a DER-encoded ECDSA signature.
+ static bool GetMaximumSignatureSize(const std::string& private_key_path,
+ size_t* signature_size);
+
private:
// This should never be constructed
DISALLOW_IMPLICIT_CONSTRUCTORS(PayloadSigner);
diff --git a/payload_generator/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
index eaf8776..bf7100b 100644
--- a/payload_generator/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -46,6 +46,8 @@
const char* kUnittestPublicKey2Path = "unittest_key2.pub.pem";
const char* kUnittestPrivateKeyRSA4096Path = "unittest_key_RSA4096.pem";
const char* kUnittestPublicKeyRSA4096Path = "unittest_key_RSA4096.pub.pem";
+const char* kUnittestPrivateKeyECPath = "unittest_key_EC.pem";
+const char* kUnittestPublicKeyECPath = "unittest_key_EC.pub.pem";
// Some data and its corresponding hash and signature:
const char kDataToSign[] = "This is some data to sign.";
@@ -115,7 +117,6 @@
EXPECT_TRUE(signatures.ParseFromString(signature));
EXPECT_EQ(1, signatures.signatures_size());
const Signatures::Signature& sig = signatures.signatures(0);
- EXPECT_EQ(1U, sig.version());
const string& sig_data = sig.data();
ASSERT_EQ(arraysize(kDataSignature), sig_data.size());
for (size_t i = 0; i < arraysize(kDataSignature); i++) {
@@ -128,22 +129,20 @@
SignSampleData(&signature,
{GetBuildArtifactsPath(kUnittestPrivateKeyPath),
GetBuildArtifactsPath(kUnittestPrivateKey2Path),
- GetBuildArtifactsPath(kUnittestPrivateKeyRSA4096Path)});
+ GetBuildArtifactsPath(kUnittestPrivateKeyRSA4096Path),
+ GetBuildArtifactsPath(kUnittestPrivateKeyECPath)});
// Either public key should pass the verification.
- string public_key;
- EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKeyPath),
- &public_key));
- EXPECT_TRUE(
- PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
- EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKey2Path),
- &public_key));
- EXPECT_TRUE(
- PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
- EXPECT_TRUE(utils::ReadFile(
- GetBuildArtifactsPath(kUnittestPublicKeyRSA4096Path), &public_key));
- EXPECT_TRUE(
- PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
+ for (const auto& path : {kUnittestPublicKeyPath,
+ kUnittestPublicKey2Path,
+ kUnittestPublicKeyRSA4096Path,
+ kUnittestPublicKeyECPath}) {
+ string public_key;
+ EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(path), &public_key));
+ auto payload_verifier = PayloadVerifier::CreateInstance(public_key);
+ EXPECT_TRUE(payload_verifier != nullptr);
+ EXPECT_TRUE(payload_verifier->VerifySignature(signature, hash_data_));
+ }
}
TEST_F(PayloadSignerTest, VerifySignatureTest) {
@@ -153,13 +152,17 @@
string public_key;
EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKeyPath),
&public_key));
- EXPECT_TRUE(
- PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
+ auto payload_verifier = PayloadVerifier::CreateInstance(public_key);
+ EXPECT_TRUE(payload_verifier != nullptr);
+ EXPECT_TRUE(payload_verifier->VerifySignature(signature, hash_data_));
+
// Passing the invalid key should fail the verification.
+ public_key.clear();
EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKey2Path),
&public_key));
- EXPECT_TRUE(
- PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
+ payload_verifier = PayloadVerifier::CreateInstance(public_key);
+ EXPECT_TRUE(payload_verifier != nullptr);
+ EXPECT_FALSE(payload_verifier->VerifySignature(signature, hash_data_));
}
TEST_F(PayloadSignerTest, SkipMetadataSignatureTest) {
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index 23d2d7e..d9c18ff 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -281,7 +281,7 @@
local option_key="$2"
local default_value="${3:-}"
local value
- if value=$(look "${option_key}=" "${file_txt}" | tail -n 1); then
+ if value=$(grep "^${option_key}=" "${file_txt}" | tail -n 1); then
if value=$(echo "${value}" | cut -f 2- -d "=" | grep -E "^[0-9]+$"); then
echo "${value}"
return
diff --git a/scripts/update_payload/update_metadata_pb2.py b/scripts/update_payload/update_metadata_pb2.py
index 7f1648b..cb8f4c2 100644
--- a/scripts/update_payload/update_metadata_pb2.py
+++ b/scripts/update_payload/update_metadata_pb2.py
@@ -1,19 +1,27 @@
+# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: update_metadata.proto
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
-from google.protobuf import descriptor_pb2
+from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
+_sym_db = _symbol_database.Default()
+
DESCRIPTOR = _descriptor.FileDescriptor(
name='update_metadata.proto',
package='chromeos_update_engine',
- serialized_pb='\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"z\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1a*\n\tSignature\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"w\n\tImageInfo\x12\r\n\x05\x62oard\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x15\n\rbuild_channel\x18\x05 \x01(\t\x12\x15\n\rbuild_version\x18\x06 \x01(\t\"\xe6\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xa5\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x08\n\x04MOVE\x10\x02\x12\n\n\x06\x42SDIFF\x10\x03\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xd7\x05\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"Y\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\"\xb1\x06\n\x14\x44\x65ltaArchiveManifest\x12\x44\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12K\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12>\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x39\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x39\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadataB\x02H\x03')
+ syntax='proto2',
+ serialized_options=_b('H\003'),
+ serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"z\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1a*\n\tSignature\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"w\n\tImageInfo\x12\r\n\x05\x62oard\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x15\n\rbuild_channel\x18\x05 \x01(\t\x12\x15\n\rbuild_version\x18\x06 \x01(\t\"\xee\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xad\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xd7\x05\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"s\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\"\xb1\x06\n\x14\x44\x65ltaArchiveManifest\x12\x44\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12K\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12>\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x39\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x39\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadataB\x02H\x03')
+)
@@ -25,54 +33,55 @@
values=[
_descriptor.EnumValueDescriptor(
name='REPLACE', index=0, number=0,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='REPLACE_BZ', index=1, number=1,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='MOVE', index=2, number=2,
- options=None,
+ serialized_options=_b('\010\001'),
type=None),
_descriptor.EnumValueDescriptor(
name='BSDIFF', index=3, number=3,
- options=None,
+ serialized_options=_b('\010\001'),
type=None),
_descriptor.EnumValueDescriptor(
name='SOURCE_COPY', index=4, number=4,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SOURCE_BSDIFF', index=5, number=5,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='REPLACE_XZ', index=6, number=8,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ZERO', index=7, number=6,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='DISCARD', index=8, number=7,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='BROTLI_BSDIFF', index=9, number=10,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='PUFFDIFF', index=10, number=9,
- options=None,
+ serialized_options=None,
type=None),
],
containing_type=None,
- options=None,
+ serialized_options=None,
serialized_start=712,
- serialized_end=877,
+ serialized_end=885,
)
+_sym_db.RegisterEnumDescriptor(_INSTALLOPERATION_TYPE)
_EXTENT = _descriptor.Descriptor(
@@ -88,23 +97,26 @@
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='num_blocks', full_name='chromeos_update_engine.Extent.num_blocks', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=49,
serialized_end=98,
)
@@ -123,23 +135,26 @@
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data', full_name='chromeos_update_engine.Signatures.Signature.data', index=1,
number=2, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=180,
serialized_end=222,
)
@@ -157,16 +172,19 @@
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_SIGNATURES_SIGNATURE, ],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=100,
serialized_end=222,
)
@@ -185,23 +203,26 @@
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash', full_name='chromeos_update_engine.PartitionInfo.hash', index=1,
number=2, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=224,
serialized_end=267,
)
@@ -217,54 +238,57 @@
_descriptor.FieldDescriptor(
name='board', full_name='chromeos_update_engine.ImageInfo.board', index=0,
number=1, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='key', full_name='chromeos_update_engine.ImageInfo.key', index=1,
number=2, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='channel', full_name='chromeos_update_engine.ImageInfo.channel', index=2,
number=3, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='version', full_name='chromeos_update_engine.ImageInfo.version', index=3,
number=4, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='build_channel', full_name='chromeos_update_engine.ImageInfo.build_channel', index=4,
number=5, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='build_version', full_name='chromeos_update_engine.ImageInfo.build_version', index=5,
number=6, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=269,
serialized_end=388,
)
@@ -283,63 +307,63 @@
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data_offset', full_name='chromeos_update_engine.InstallOperation.data_offset', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data_length', full_name='chromeos_update_engine.InstallOperation.data_length', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_extents', full_name='chromeos_update_engine.InstallOperation.src_extents', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_length', full_name='chromeos_update_engine.InstallOperation.src_length', index=4,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dst_extents', full_name='chromeos_update_engine.InstallOperation.dst_extents', index=5,
number=6, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dst_length', full_name='chromeos_update_engine.InstallOperation.dst_length', index=6,
number=7, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data_sha256_hash', full_name='chromeos_update_engine.InstallOperation.data_sha256_hash', index=7,
number=8, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_sha256_hash', full_name='chromeos_update_engine.InstallOperation.src_sha256_hash', index=8,
number=9, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@@ -347,11 +371,14 @@
enum_types=[
_INSTALLOPERATION_TYPE,
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=391,
- serialized_end=877,
+ serialized_end=885,
)
@@ -365,126 +392,129 @@
_descriptor.FieldDescriptor(
name='partition_name', full_name='chromeos_update_engine.PartitionUpdate.partition_name', index=0,
number=1, type=9, cpp_type=9, label=2,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='run_postinstall', full_name='chromeos_update_engine.PartitionUpdate.run_postinstall', index=1,
number=2, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='postinstall_path', full_name='chromeos_update_engine.PartitionUpdate.postinstall_path', index=2,
number=3, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='filesystem_type', full_name='chromeos_update_engine.PartitionUpdate.filesystem_type', index=3,
number=4, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_partition_signature', full_name='chromeos_update_engine.PartitionUpdate.new_partition_signature', index=4,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='old_partition_info', full_name='chromeos_update_engine.PartitionUpdate.old_partition_info', index=5,
number=6, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_partition_info', full_name='chromeos_update_engine.PartitionUpdate.new_partition_info', index=6,
number=7, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='operations', full_name='chromeos_update_engine.PartitionUpdate.operations', index=7,
number=8, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='postinstall_optional', full_name='chromeos_update_engine.PartitionUpdate.postinstall_optional', index=8,
number=9, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_data_extent', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_data_extent', index=9,
number=10, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_extent', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_extent', index=10,
number=11, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_algorithm', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_algorithm', index=11,
number=12, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_salt', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_salt', index=12,
number=13, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fec_data_extent', full_name='chromeos_update_engine.PartitionUpdate.fec_data_extent', index=13,
number=14, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fec_extent', full_name='chromeos_update_engine.PartitionUpdate.fec_extent', index=14,
number=15, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fec_roots', full_name='chromeos_update_engine.PartitionUpdate.fec_roots', index=15,
number=16, type=13, cpp_type=3, label=1,
has_default_value=True, default_value=2,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=880,
- serialized_end=1607,
+ oneofs=[
+ ],
+ serialized_start=888,
+ serialized_end=1615,
)
@@ -498,35 +528,38 @@
_descriptor.FieldDescriptor(
name='name', full_name='chromeos_update_engine.DynamicPartitionGroup.name', index=0,
number=1, type=9, cpp_type=9, label=2,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='size', full_name='chromeos_update_engine.DynamicPartitionGroup.size', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='partition_names', full_name='chromeos_update_engine.DynamicPartitionGroup.partition_names', index=2,
number=3, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=1609,
- serialized_end=1685,
+ oneofs=[
+ ],
+ serialized_start=1617,
+ serialized_end=1693,
)
@@ -543,18 +576,28 @@
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='snapshot_enabled', full_name='chromeos_update_engine.DynamicPartitionMetadata.snapshot_enabled', index=1,
+ number=2, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=1687,
- serialized_end=1776,
+ oneofs=[
+ ],
+ serialized_start=1695,
+ serialized_end=1810,
)
@@ -571,124 +614,127 @@
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='kernel_install_operations', full_name='chromeos_update_engine.DeltaArchiveManifest.kernel_install_operations', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='block_size', full_name='chromeos_update_engine.DeltaArchiveManifest.block_size', index=2,
number=3, type=13, cpp_type=3, label=1,
has_default_value=True, default_value=4096,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='signatures_offset', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_offset', index=3,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='signatures_size', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_size', index=4,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='old_kernel_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_kernel_info', index=5,
number=6, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_kernel_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_kernel_info', index=6,
number=7, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='old_rootfs_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_rootfs_info', index=7,
number=8, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_rootfs_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_rootfs_info', index=8,
number=9, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='old_image_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_image_info', index=9,
number=10, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_image_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_image_info', index=10,
number=11, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='minor_version', full_name='chromeos_update_engine.DeltaArchiveManifest.minor_version', index=11,
number=12, type=13, cpp_type=3, label=1,
has_default_value=True, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='partitions', full_name='chromeos_update_engine.DeltaArchiveManifest.partitions', index=12,
number=13, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='max_timestamp', full_name='chromeos_update_engine.DeltaArchiveManifest.max_timestamp', index=13,
number=14, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dynamic_partition_metadata', full_name='chromeos_update_engine.DeltaArchiveManifest.dynamic_partition_metadata', index=14,
number=15, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=1779,
- serialized_end=2596,
+ oneofs=[
+ ],
+ serialized_start=1813,
+ serialized_end=2630,
)
-_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES;
+_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES
_SIGNATURES.fields_by_name['signatures'].message_type = _SIGNATURES_SIGNATURE
_INSTALLOPERATION.fields_by_name['type'].enum_type = _INSTALLOPERATION_TYPE
_INSTALLOPERATION.fields_by_name['src_extents'].message_type = _EXTENT
_INSTALLOPERATION.fields_by_name['dst_extents'].message_type = _EXTENT
-_INSTALLOPERATION_TYPE.containing_type = _INSTALLOPERATION;
+_INSTALLOPERATION_TYPE.containing_type = _INSTALLOPERATION
_PARTITIONUPDATE.fields_by_name['new_partition_signature'].message_type = _SIGNATURES_SIGNATURE
_PARTITIONUPDATE.fields_by_name['old_partition_info'].message_type = _PARTITIONINFO
_PARTITIONUPDATE.fields_by_name['new_partition_info'].message_type = _PARTITIONINFO
@@ -717,68 +763,81 @@
DESCRIPTOR.message_types_by_name['DynamicPartitionGroup'] = _DYNAMICPARTITIONGROUP
DESCRIPTOR.message_types_by_name['DynamicPartitionMetadata'] = _DYNAMICPARTITIONMETADATA
DESCRIPTOR.message_types_by_name['DeltaArchiveManifest'] = _DELTAARCHIVEMANIFEST
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-class Extent(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _EXTENT
-
+Extent = _reflection.GeneratedProtocolMessageType('Extent', (_message.Message,), {
+ 'DESCRIPTOR' : _EXTENT,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.Extent)
+ })
+_sym_db.RegisterMessage(Extent)
-class Signatures(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
+Signatures = _reflection.GeneratedProtocolMessageType('Signatures', (_message.Message,), {
- class Signature(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _SIGNATURES_SIGNATURE
-
+ 'Signature' : _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), {
+ 'DESCRIPTOR' : _SIGNATURES_SIGNATURE,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures.Signature)
- DESCRIPTOR = _SIGNATURES
-
+ })
+ ,
+ 'DESCRIPTOR' : _SIGNATURES,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures)
+ })
+_sym_db.RegisterMessage(Signatures)
+_sym_db.RegisterMessage(Signatures.Signature)
-class PartitionInfo(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _PARTITIONINFO
-
+PartitionInfo = _reflection.GeneratedProtocolMessageType('PartitionInfo', (_message.Message,), {
+ 'DESCRIPTOR' : _PARTITIONINFO,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionInfo)
+ })
+_sym_db.RegisterMessage(PartitionInfo)
-class ImageInfo(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _IMAGEINFO
-
+ImageInfo = _reflection.GeneratedProtocolMessageType('ImageInfo', (_message.Message,), {
+ 'DESCRIPTOR' : _IMAGEINFO,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.ImageInfo)
+ })
+_sym_db.RegisterMessage(ImageInfo)
-class InstallOperation(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _INSTALLOPERATION
-
+InstallOperation = _reflection.GeneratedProtocolMessageType('InstallOperation', (_message.Message,), {
+ 'DESCRIPTOR' : _INSTALLOPERATION,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.InstallOperation)
+ })
+_sym_db.RegisterMessage(InstallOperation)
-class PartitionUpdate(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _PARTITIONUPDATE
-
+PartitionUpdate = _reflection.GeneratedProtocolMessageType('PartitionUpdate', (_message.Message,), {
+ 'DESCRIPTOR' : _PARTITIONUPDATE,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionUpdate)
+ })
+_sym_db.RegisterMessage(PartitionUpdate)
-class DynamicPartitionGroup(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _DYNAMICPARTITIONGROUP
-
+DynamicPartitionGroup = _reflection.GeneratedProtocolMessageType('DynamicPartitionGroup', (_message.Message,), {
+ 'DESCRIPTOR' : _DYNAMICPARTITIONGROUP,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.DynamicPartitionGroup)
+ })
+_sym_db.RegisterMessage(DynamicPartitionGroup)
-class DynamicPartitionMetadata(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _DYNAMICPARTITIONMETADATA
-
+DynamicPartitionMetadata = _reflection.GeneratedProtocolMessageType('DynamicPartitionMetadata', (_message.Message,), {
+ 'DESCRIPTOR' : _DYNAMICPARTITIONMETADATA,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.DynamicPartitionMetadata)
+ })
+_sym_db.RegisterMessage(DynamicPartitionMetadata)
-class DeltaArchiveManifest(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _DELTAARCHIVEMANIFEST
-
+DeltaArchiveManifest = _reflection.GeneratedProtocolMessageType('DeltaArchiveManifest', (_message.Message,), {
+ 'DESCRIPTOR' : _DELTAARCHIVEMANIFEST,
+ '__module__' : 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.DeltaArchiveManifest)
+ })
+_sym_db.RegisterMessage(DeltaArchiveManifest)
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003')
+DESCRIPTOR._options = None
+_INSTALLOPERATION_TYPE.values_by_name["MOVE"]._options = None
+_INSTALLOPERATION_TYPE.values_by_name["BSDIFF"]._options = None
# @@protoc_insertion_point(module_scope)
diff --git a/unittest_key_EC.pem b/unittest_key_EC.pem
new file mode 100644
index 0000000..9e65a68
--- /dev/null
+++ b/unittest_key_EC.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGaguGj8Yb1KkqKHd
+ISblUsjtOCbzAuVpX81i02sm8FWhRANCAARBnuotwKOsuvjH6iwTDhOAi7Q5pLWz
+xDkZjg2pcfbfi9FFTvLYETas7B2W6fx9PUezUmHTFTDV2JZuMYYFdZOw
+-----END PRIVATE KEY-----
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 08f6c20..5bffc42 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -39,6 +39,7 @@
#include "update_engine/metrics_reporter_interface.h"
#include "update_engine/metrics_utils.h"
#include "update_engine/network_selector.h"
+#include "update_engine/payload_consumer/certificate_parser_interface.h"
#include "update_engine/payload_consumer/delta_performer.h"
#include "update_engine/payload_consumer/download_action.h"
#include "update_engine/payload_consumer/file_descriptor.h"
@@ -46,6 +47,7 @@
#include "update_engine/payload_consumer/filesystem_verifier_action.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_consumer/payload_metadata.h"
+#include "update_engine/payload_consumer/payload_verifier.h"
#include "update_engine/payload_consumer/postinstall_runner_action.h"
#include "update_engine/update_boot_flags_action.h"
#include "update_engine/update_status_utils.h"
@@ -410,12 +412,16 @@
}
fd->Close();
- string public_key;
- if (!utils::ReadFile(constants::kUpdatePayloadPublicKeyPath, &public_key)) {
- return LogAndSetError(error, FROM_HERE, "Failed to read public key.");
+ auto payload_verifier = PayloadVerifier::CreateInstanceFromZipPath(
+ constants::kUpdateCertificatesPath);
+ if (!payload_verifier) {
+ return LogAndSetError(error,
+ FROM_HERE,
+ "Failed to create the payload verifier from " +
+ std::string(constants::kUpdateCertificatesPath));
}
- errorcode =
- payload_metadata.ValidateMetadataSignature(metadata, "", public_key);
+ errorcode = payload_metadata.ValidateMetadataSignature(
+ metadata, "", *payload_verifier);
if (errorcode != ErrorCode::kSuccess) {
return LogAndSetError(error,
FROM_HERE,
diff --git a/update_metadata.proto b/update_metadata.proto
index 1657a7e..9bc0d8a 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -126,8 +126,17 @@
message Signatures {
message Signature {
- optional uint32 version = 1;
+ optional uint32 version = 1 [deprecated = true];
optional bytes data = 2;
+
+ // The DER encoded signature size of EC keys is nondeterministic for
+ // different input of sha256 hash. However, we need the size of the
+ // serialized signatures protobuf string to be fixed before signing;
+ // because this size is part of the content to be signed. Therefore, we
+ // always pad the signature data to the maximum possible signature size of
+ // a given key. And the payload verifier will truncate the signature to
+ // its correct size based on the value of |unpadded_signature_size|.
+ optional fixed32 unpadded_signature_size = 3;
}
repeated Signature signatures = 1;
}