Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: chrome/browser/extensions/extensions_service.cc

Issue 126014: Verify signed .crx extension installations (Closed)
Patch Set: final changes Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extensions_service.h" 5 #include "chrome/browser/extensions/extensions_service.h"
6 6
7 #include "app/l10n_util.h" 7 #include "app/l10n_util.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/crypto/signature_verifier.h"
9 #include "base/file_util.h" 10 #include "base/file_util.h"
10 #include "base/gfx/png_encoder.h" 11 #include "base/gfx/png_encoder.h"
11 #include "base/scoped_handle.h" 12 #include "base/scoped_handle.h"
12 #include "base/scoped_temp_dir.h" 13 #include "base/scoped_temp_dir.h"
13 #include "base/string_util.h" 14 #include "base/string_util.h"
14 #include "base/third_party/nss/blapi.h" 15 #include "base/third_party/nss/blapi.h"
15 #include "base/third_party/nss/sha256.h" 16 #include "base/third_party/nss/sha256.h"
16 #include "base/thread.h" 17 #include "base/thread.h"
17 #include "base/values.h" 18 #include "base/values.h"
18 #include "net/base/file_stream.h" 19 #include "net/base/file_stream.h"
19 #include "chrome/browser/browser.h" 20 #include "chrome/browser/browser.h"
20 #include "chrome/browser/browser_list.h" 21 #include "chrome/browser/browser_list.h"
21 #include "chrome/browser/browser_process.h" 22 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_thread.h" 23 #include "chrome/browser/chrome_thread.h"
24 #include "chrome/browser/extensions/extension_creator.h"
23 #include "chrome/browser/extensions/extension_browser_event_router.h" 25 #include "chrome/browser/extensions/extension_browser_event_router.h"
24 #include "chrome/browser/extensions/extension_process_manager.h" 26 #include "chrome/browser/extensions/extension_process_manager.h"
25 #include "chrome/browser/extensions/external_extension_provider.h" 27 #include "chrome/browser/extensions/external_extension_provider.h"
26 #include "chrome/browser/extensions/external_pref_extension_provider.h" 28 #include "chrome/browser/extensions/external_pref_extension_provider.h"
27 #include "chrome/browser/profile.h" 29 #include "chrome/browser/profile.h"
28 #include "chrome/browser/utility_process_host.h" 30 #include "chrome/browser/utility_process_host.h"
29 #include "chrome/common/chrome_switches.h" 31 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/extensions/extension.h" 32 #include "chrome/common/extensions/extension.h"
31 #include "chrome/common/extensions/extension_error_reporter.h" 33 #include "chrome/common/extensions/extension_error_reporter.h"
32 #include "chrome/common/extensions/extension_unpacker.h" 34 #include "chrome/common/extensions/extension_unpacker.h"
33 #include "chrome/common/json_value_serializer.h" 35 #include "chrome/common/json_value_serializer.h"
34 #include "chrome/common/notification_service.h" 36 #include "chrome/common/notification_service.h"
35 #include "chrome/common/pref_names.h" 37 #include "chrome/common/pref_names.h"
36 #include "chrome/common/pref_service.h" 38 #include "chrome/common/pref_service.h"
37 #include "chrome/common/zip.h" 39 #include "chrome/common/zip.h"
38 #include "chrome/common/url_constants.h" 40 #include "chrome/common/url_constants.h"
39 #include "grit/chromium_strings.h" 41 #include "grit/chromium_strings.h"
40 #include "grit/generated_resources.h" 42 #include "grit/generated_resources.h"
43 #include "net/base/base64.h"
41 #include "third_party/skia/include/core/SkBitmap.h" 44 #include "third_party/skia/include/core/SkBitmap.h"
42 45
43 #if defined(OS_WIN) 46 #if defined(OS_WIN)
44 #include "app/win_util.h" 47 #include "app/win_util.h"
45 #include "base/win_util.h" 48 #include "base/win_util.h"
46 #include "chrome/browser/extensions/external_registry_extension_provider_win.h" 49 #include "chrome/browser/extensions/external_registry_extension_provider_win.h"
47 #endif 50 #endif
48 51
49 // ExtensionsService. 52 // ExtensionsService.
50 53
54 const char ExtensionsService::kExtensionHeaderMagic[] = "Cr24";
55
51 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; 56 const char* ExtensionsService::kInstallDirectoryName = "Extensions";
52 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; 57 const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
53 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL"; 58 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL";
54 59
55 namespace { 60 namespace {
56 61
57 // A preference that keeps track of extension settings. This is a dictionary 62 // A preference that keeps track of extension settings. This is a dictionary
58 // object read from the Preferences file, keyed off of extension id's. 63 // object read from the Preferences file, keyed off of extension id's.
59 const wchar_t kExternalExtensionsPref[] = L"extensions.settings"; 64 const wchar_t kExternalExtensionsPref[] = L"extensions.settings";
60 65
61 // A preference keeping track of how the extension was installed. 66 // A preference keeping track of how the extension was installed.
62 const wchar_t kLocation[] = L"location"; 67 const wchar_t kLocation[] = L"location";
63 const wchar_t kState[] = L"state"; 68 const wchar_t kState[] = L"state";
64 69
65 // A temporary subdirectory where we unpack extensions. 70 // A temporary subdirectory where we unpack extensions.
66 const char* kUnpackExtensionDir = "TEMP_UNPACK"; 71 const char* kUnpackExtensionDir = "TEMP_UNPACK";
67 72
68 // The version of the extension package that this code understands. 73 // Unpacking errors
69 const uint32 kExpectedVersion = 1; 74 const char* kBadMagicNumberError = "Bad magic number";
75 const char* kBadHeaderSizeError = "Excessively large key or signature";
76 const char* kBadVersionNumberError = "Bad version number";
77 const char* kInvalidExtensionHeaderError = "Invalid extension header";
78 const char* kInvalidPublicKeyError = "Invalid public key";
79 const char* kInvalidSignatureError = "Invalid signature";
80 const char* kSignatureVerificationFailed = "Signature verification failed";
81 const char* kSignatureVerificationInitFailed =
82 "Signature verification initialization failed. This is most likely "
83 "caused by a public key in the wrong format (should encode algorithm).";
70 } 84 }
71 85
72 // This class coordinates an extension unpack task which is run in a separate 86 // This class coordinates an extension unpack task which is run in a separate
73 // process. Results are sent back to this class, which we route to the 87 // process. Results are sent back to this class, which we route to the
74 // ExtensionServiceBackend. 88 // ExtensionServiceBackend.
75 class ExtensionsServiceBackend::UnpackerClient 89 class ExtensionsServiceBackend::UnpackerClient
76 : public UtilityProcessHost::Client { 90 : public UtilityProcessHost::Client {
77 public: 91 public:
78 UnpackerClient(ExtensionsServiceBackend* backend, 92 UnpackerClient(ExtensionsServiceBackend* backend,
79 const FilePath& extension_path, 93 const FilePath& extension_path,
94 const std::string& public_key,
80 const std::string& expected_id, 95 const std::string& expected_id,
81 bool from_external) 96 bool from_external)
82 : backend_(backend), extension_path_(extension_path), 97 : backend_(backend), extension_path_(extension_path),
83 expected_id_(expected_id), from_external_(from_external), 98 public_key_(public_key), expected_id_(expected_id),
84 got_response_(false) { 99 from_external_(from_external), got_response_(false) {
85 } 100 }
86 101
87 // Starts the unpack task. We call back to the backend when the task is done, 102 // Starts the unpack task. We call back to the backend when the task is done,
88 // or a problem occurs. 103 // or a problem occurs.
89 void Start() { 104 void Start() {
90 AddRef(); // balanced in OnUnpackExtensionReply() 105 AddRef(); // balanced in OnUnpackExtensionReply()
91 106
92 // TODO(mpcomplete): handle multiple installs 107 // TODO(mpcomplete): handle multiple installs
93 FilePath temp_dir = backend_->install_directory_.AppendASCII( 108 FilePath temp_dir = backend_->install_directory_.AppendASCII(
94 kUnpackExtensionDir); 109 kUnpackExtensionDir);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 &images)) { 154 &images)) {
140 OnUnpackExtensionFailed("Couldn't read image data from disk."); 155 OnUnpackExtensionFailed("Couldn't read image data from disk.");
141 } else { 156 } else {
142 OnUnpackExtensionSucceededImpl(manifest, images); 157 OnUnpackExtensionSucceededImpl(manifest, images);
143 } 158 }
144 } 159 }
145 160
146 void OnUnpackExtensionSucceededImpl( 161 void OnUnpackExtensionSucceededImpl(
147 const DictionaryValue& manifest, 162 const DictionaryValue& manifest,
148 const ExtensionUnpacker::DecodedImages& images) { 163 const ExtensionUnpacker::DecodedImages& images) {
164 // Add our public key into the parsed manifest. We want it to be saved so
165 // that we can later refer to it (eg for generating ids, validating
166 // signatures, etc).
167 // The const_cast is hacky, but seems like the right thing here, rather than
168 // making a full copy just to make this change.
169 const_cast<DictionaryValue*>(&manifest)->SetString(
170 Extension::kPublicKeyKey, public_key_);
171
149 // The extension was unpacked to the temp dir inside our unpacking dir. 172 // The extension was unpacked to the temp dir inside our unpacking dir.
150 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( 173 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII(
151 ExtensionsServiceBackend::kTempExtensionName); 174 ExtensionsServiceBackend::kTempExtensionName);
152 backend_->OnExtensionUnpacked(extension_path_, extension_dir, 175 backend_->OnExtensionUnpacked(extension_path_, extension_dir,
153 expected_id_, from_external_, 176 expected_id_, from_external_,
154 manifest, images); 177 manifest, images);
155 Cleanup(); 178 Cleanup();
156 } 179 }
157 180
158 virtual void OnUnpackExtensionFailed(const std::string& error_message) { 181 virtual void OnUnpackExtensionFailed(const std::string& error_message) {
(...skipping 16 matching lines...) Expand all
175 MessageLoop* file_loop) { 198 MessageLoop* file_loop) {
176 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); 199 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop);
177 host->StartExtensionUnpacker(temp_extension_path_); 200 host->StartExtensionUnpacker(temp_extension_path_);
178 } 201 }
179 202
180 scoped_refptr<ExtensionsServiceBackend> backend_; 203 scoped_refptr<ExtensionsServiceBackend> backend_;
181 204
182 // The path to the crx file that we're installing. 205 // The path to the crx file that we're installing.
183 FilePath extension_path_; 206 FilePath extension_path_;
184 207
208 // The public key of the extension we're installing.
209 std::string public_key_;
210
185 // The path to the copy of the crx file in the temporary directory where we're 211 // The path to the copy of the crx file in the temporary directory where we're
186 // unpacking it. 212 // unpacking it.
187 FilePath temp_extension_path_; 213 FilePath temp_extension_path_;
188 214
189 // The ID we expect this extension to have, if any. 215 // The ID we expect this extension to have, if any.
190 std::string expected_id_; 216 std::string expected_id_;
191 217
192 // True if this is being installed from an external source. 218 // True if this is being installed from an external source.
193 bool from_external_; 219 bool from_external_;
194 220
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 374
349 NotificationService::current()->Notify( 375 NotificationService::current()->Notify(
350 NotificationType::EXTENSIONS_LOADED, 376 NotificationType::EXTENSIONS_LOADED,
351 NotificationService::AllSources(), 377 NotificationService::AllSources(),
352 Details<ExtensionList>(&enabled_extensions)); 378 Details<ExtensionList>(&enabled_extensions));
353 379
354 delete new_extensions; 380 delete new_extensions;
355 } 381 }
356 382
357 void ExtensionsService::OnExtensionInstalled(Extension* extension, 383 void ExtensionsService::OnExtensionInstalled(Extension* extension,
358 bool update) { 384 Extension::InstallType install_type) {
359 UpdateExtensionPref(ASCIIToWide(extension->id()), kState, 385 UpdateExtensionPref(ASCIIToWide(extension->id()), kState,
360 Value::CreateIntegerValue(Extension::ENABLED), false); 386 Value::CreateIntegerValue(Extension::ENABLED), false);
361 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation, 387 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation,
362 Value::CreateIntegerValue(Extension::INTERNAL), true); 388 Value::CreateIntegerValue(Extension::INTERNAL), true);
363 389
364 // If the extension is a theme, tell the profile (and therefore ThemeProvider) 390 // If the extension is a theme, tell the profile (and therefore ThemeProvider)
365 // to apply it. 391 // to apply it.
366 if (extension->IsTheme()) { 392 if (extension->IsTheme()) {
367 NotificationService::current()->Notify( 393 NotificationService::current()->Notify(
368 NotificationType::THEME_INSTALLED, 394 NotificationType::THEME_INSTALLED,
369 NotificationService::AllSources(), 395 NotificationService::AllSources(),
370 Details<Extension>(extension)); 396 Details<Extension>(extension));
371 } else { 397 } else {
372 NotificationService::current()->Notify( 398 NotificationService::current()->Notify(
373 NotificationType::EXTENSION_INSTALLED, 399 NotificationType::EXTENSION_INSTALLED,
374 NotificationService::AllSources(), 400 NotificationService::AllSources(),
375 Details<Extension>(extension)); 401 Details<Extension>(extension));
376 } 402 }
377 } 403 }
378 404
379 void ExtensionsService::OnExternalExtensionInstalled( 405 void ExtensionsService::OnExternalExtensionInstalled(
380 const std::string& id, Extension::Location location) { 406 const std::string& id, Extension::Location location) {
381 DCHECK(Extension::IsExternalLocation(location)); 407 DCHECK(Extension::IsExternalLocation(location));
382 UpdateExtensionPref(ASCIIToWide(id), kState, 408 UpdateExtensionPref(ASCIIToWide(id), kState,
383 Value::CreateIntegerValue(Extension::ENABLED), false); 409 Value::CreateIntegerValue(Extension::ENABLED), false);
384 UpdateExtensionPref(ASCIIToWide(id), kLocation, 410 UpdateExtensionPref(ASCIIToWide(id), kLocation,
385 Value::CreateIntegerValue(location), true); 411 Value::CreateIntegerValue(location), true);
386 } 412 }
387 413
388 void ExtensionsService::OnExtensionVersionReinstalled(const std::string& id) { 414 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) {
389 Extension* extension = GetExtensionByID(id); 415 Extension* extension = GetExtensionByID(id);
390 if (extension && extension->IsTheme()) { 416 if (extension && extension->IsTheme()) {
391 NotificationService::current()->Notify( 417 NotificationService::current()->Notify(
392 NotificationType::THEME_INSTALLED, 418 NotificationType::THEME_INSTALLED,
393 NotificationService::AllSources(), 419 NotificationService::AllSources(),
394 Details<Extension>(extension)); 420 Details<Extension>(extension));
395 } 421 }
396 } 422 }
397 423
398 Extension* ExtensionsService::GetExtensionByID(std::string id) { 424 Extension* ExtensionsService::GetExtensionByID(std::string id) {
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 Extension* extension = LoadExtension(extension_path, 649 Extension* extension = LoadExtension(extension_path,
624 Extension::LOAD, 650 Extension::LOAD,
625 false); // don't require ID 651 false); // don't require ID
626 if (extension) { 652 if (extension) {
627 ExtensionList* extensions = new ExtensionList; 653 ExtensionList* extensions = new ExtensionList;
628 extensions->push_back(extension); 654 extensions->push_back(extension);
629 ReportExtensionsLoaded(extensions); 655 ReportExtensionsLoaded(extensions);
630 } 656 }
631 } 657 }
632 658
659 DictionaryValue* ExtensionsServiceBackend::ReadManifest(FilePath manifest_path,
660 std::string* error) {
661 JSONFileValueSerializer serializer(manifest_path);
662 scoped_ptr<Value> root(serializer.Deserialize(error));
663 if (!root.get())
664 return NULL;
665
666 if (!root->IsType(Value::TYPE_DICTIONARY)) {
667 *error = Extension::kInvalidManifestError;
668 return NULL;
669 }
670
671 return static_cast<DictionaryValue*>(root.release());
672 }
673
633 Extension* ExtensionsServiceBackend::LoadExtension( 674 Extension* ExtensionsServiceBackend::LoadExtension(
634 const FilePath& extension_path, 675 const FilePath& extension_path,
635 Extension::Location location, 676 Extension::Location location,
636 bool require_id) { 677 bool require_id) {
637 FilePath manifest_path = 678 FilePath manifest_path =
638 extension_path.AppendASCII(Extension::kManifestFilename); 679 extension_path.AppendASCII(Extension::kManifestFilename);
639 if (!file_util::PathExists(manifest_path)) { 680 if (!file_util::PathExists(manifest_path)) {
640 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); 681 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError);
641 return NULL; 682 return NULL;
642 } 683 }
643 684
644 JSONFileValueSerializer serializer(manifest_path);
645 std::string error; 685 std::string error;
646 scoped_ptr<Value> root(serializer.Deserialize(&error)); 686 scoped_ptr<DictionaryValue> root(ReadManifest(manifest_path, &error));
647 if (!root.get()) { 687 if (!root.get()) {
648 ReportExtensionLoadError(extension_path, error); 688 ReportExtensionLoadError(extension_path, error);
649 return NULL; 689 return NULL;
650 } 690 }
651 691
652 if (!root->IsType(Value::TYPE_DICTIONARY)) {
653 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError);
654 return NULL;
655 }
656
657 scoped_ptr<Extension> extension(new Extension(extension_path)); 692 scoped_ptr<Extension> extension(new Extension(extension_path));
658 if (!extension->InitFromValue(*static_cast<DictionaryValue*>(root.get()), 693 if (!extension->InitFromValue(*root.get(), require_id, &error)) {
659 require_id, &error)) {
660 ReportExtensionLoadError(extension_path, error); 694 ReportExtensionLoadError(extension_path, error);
661 return NULL; 695 return NULL;
662 } 696 }
663 697
664 extension->set_location(location); 698 extension->set_location(location);
665 699
666 // Theme resource validation. 700 // Theme resource validation.
667 if (extension->IsTheme()) { 701 if (extension->IsTheme()) {
668 DictionaryValue* images_value = extension->GetThemeImages(); 702 DictionaryValue* images_value = extension->GetThemeImages();
669 DictionaryValue::key_iterator iter = images_value->begin_keys(); 703 DictionaryValue::key_iterator iter = images_value->begin_keys();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName); 792 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName);
759 if (file_util::PathExists(current_version)) { 793 if (file_util::PathExists(current_version)) {
760 if (file_util::ReadFileToString(current_version, version_string)) { 794 if (file_util::ReadFileToString(current_version, version_string)) {
761 TrimWhitespace(*version_string, TRIM_ALL, version_string); 795 TrimWhitespace(*version_string, TRIM_ALL, version_string);
762 return true; 796 return true;
763 } 797 }
764 } 798 }
765 return false; 799 return false;
766 } 800 }
767 801
768 bool ExtensionsServiceBackend::CheckCurrentVersion( 802 Extension::InstallType ExtensionsServiceBackend::CompareToInstalledVersion(
803 const std::string& id,
769 const std::string& new_version_str, 804 const std::string& new_version_str,
770 const std::string& current_version_str, 805 std::string *current_version_str) {
771 const FilePath& dest_dir) { 806 CHECK(current_version_str);
807 FilePath dir(install_directory_.AppendASCII(id.c_str()));
808 if (!ReadCurrentVersion(dir, current_version_str))
809 return Extension::NEW_INSTALL;
810
772 scoped_ptr<Version> current_version( 811 scoped_ptr<Version> current_version(
773 Version::GetVersionFromString(current_version_str)); 812 Version::GetVersionFromString(*current_version_str));
774 scoped_ptr<Version> new_version( 813 scoped_ptr<Version> new_version(
775 Version::GetVersionFromString(new_version_str)); 814 Version::GetVersionFromString(new_version_str));
776 if (current_version->CompareTo(*new_version) >= 0) { 815 int comp = new_version->CompareTo(*current_version);
777 // Verify that the directory actually exists. If it doesn't we'll return 816 if (comp > 0)
778 // true so that the install code will repair the broken installation. 817 return Extension::UPGRADE;
779 // TODO(erikkay): A further step would be to verify that the extension 818 else if (comp == 0)
780 // has actually loaded successfully. 819 return Extension::REINSTALL;
781 FilePath version_dir = dest_dir.AppendASCII(current_version_str); 820 else
782 if (file_util::PathExists(version_dir)) { 821 return Extension::DOWNGRADE;
783 std::string id = WideToASCII(dest_dir.BaseName().ToWStringHack()); 822 }
784 StringToLowerASCII(&id); 823
785 ReportExtensionVersionReinstalled(id); 824 bool ExtensionsServiceBackend::NeedsReinstall(const std::string& id,
786 return false; 825 const std::string& current_version) {
787 } 826 // Verify that the directory actually exists.
788 } 827 // TODO(erikkay): A further step would be to verify that the extension
789 return true; 828 // has actually loaded successfully.
829 FilePath dir(install_directory_.AppendASCII(id.c_str()));
830 FilePath version_dir(dir.AppendASCII(current_version));
831 return !file_util::PathExists(version_dir);
790 } 832 }
791 833
792 bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir, 834 bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir,
793 const FilePath& dest_dir) { 835 const FilePath& dest_dir) {
794 if (file_util::PathExists(dest_dir)) { 836 if (file_util::PathExists(dest_dir)) {
795 // By the time we get here, it should be safe to assume that this directory 837 // By the time we get here, it should be safe to assume that this directory
796 // is not currently in use (it's not the current active version). 838 // is not currently in use (it's not the current active version).
797 if (!file_util::Delete(dest_dir, true)) { 839 if (!file_util::Delete(dest_dir, true)) {
798 ReportExtensionInstallError(source_dir, 840 ReportExtensionInstallError(source_dir,
799 "Can't delete existing version directory."); 841 "Can't delete existing version directory.");
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 LOG(INFO) << "Installing extension " << extension_path.value(); 908 LOG(INFO) << "Installing extension " << extension_path.value();
867 909
868 frontend_ = frontend; 910 frontend_ = frontend;
869 alert_on_error_ = true; 911 alert_on_error_ = true;
870 912
871 bool from_external = false; 913 bool from_external = false;
872 InstallOrUpdateExtension(extension_path, std::string(), from_external); 914 InstallOrUpdateExtension(extension_path, std::string(), from_external);
873 } 915 }
874 916
875 void ExtensionsServiceBackend::InstallOrUpdateExtension( 917 void ExtensionsServiceBackend::InstallOrUpdateExtension(
876 const FilePath& extension_path, const std::string& expected_id, 918 const FilePath& extension_path,
919 const std::string& expected_id,
877 bool from_external) { 920 bool from_external) {
878 UnpackerClient* client = 921 std::string actual_public_key;
879 new UnpackerClient(this, extension_path, expected_id, from_external); 922 if (!ValidateSignature(extension_path, &actual_public_key))
923 return; // Failures reported within ValidateSignature().
924
925 UnpackerClient* client = new UnpackerClient(
926 this, extension_path, actual_public_key, expected_id, from_external);
880 client->Start(); 927 client->Start();
881 } 928 }
882 929
930 bool ExtensionsServiceBackend::ValidateSignature(const FilePath& extension_path,
931 std::string* key_out) {
932 ScopedStdioHandle file(file_util::OpenFile(extension_path, "rb"));
933 if (!file.get()) {
934 ReportExtensionInstallError(extension_path, "Could not open file.");
935 return NULL;
936 }
937
938 // Read and verify the header.
939 ExtensionsService::ExtensionHeader header;
940 size_t len;
941
942 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it
943 // appears that we don't have any endian/alignment aware serialization
944 // code in the code base. So for now, this assumes that we're running
945 // on a little endian machine with 4 byte alignment.
946 len = fread(&header, 1, sizeof(ExtensionsService::ExtensionHeader),
947 file.get());
948 if (len < sizeof(ExtensionsService::ExtensionHeader)) {
949 ReportExtensionInstallError(extension_path, kInvalidExtensionHeaderError);
950 return false;
951 }
952 if (strncmp(ExtensionsService::kExtensionHeaderMagic, header.magic,
953 sizeof(header.magic))) {
954 ReportExtensionInstallError(extension_path, kBadMagicNumberError);
955 return false;
956 }
957 if (header.version != ExtensionsService::kCurrentVersion) {
958 ReportExtensionInstallError(extension_path, kBadVersionNumberError);
959 return false;
960 }
961 if (header.key_size > ExtensionsService::kMaxPublicKeySize ||
962 header.signature_size > ExtensionsService::kMaxSignatureSize) {
963 ReportExtensionInstallError(extension_path, kBadHeaderSizeError);
964 return false;
965 }
966
967 std::vector<uint8> key;
968 key.resize(header.key_size);
969 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
970 if (len < header.key_size) {
971 ReportExtensionInstallError(extension_path, kInvalidPublicKeyError);
972 return false;
973 }
974
975 std::vector<uint8> signature;
976 signature.resize(header.signature_size);
977 len = fread(&signature.front(), sizeof(uint8), header.signature_size,
978 file.get());
979 if (len < header.signature_size) {
980 ReportExtensionInstallError(extension_path, kInvalidSignatureError);
981 return false;
982 }
983
984 // Note: this structure is an ASN.1 which encodes the algorithm used
985 // with its parameters. This is defined in PKCS #1 v2.1 (RFC 3447).
986 // It is encoding: { OID sha1WithRSAEncryption PARAMETERS NULL }
987 // TODO(aa): This needs to be factored away someplace common.
988 const uint8 signature_algorithm[15] = {
989 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
990 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00
991 };
992
993 base::SignatureVerifier verifier;
994 if (!verifier.VerifyInit(signature_algorithm,
995 sizeof(signature_algorithm),
996 &signature.front(),
997 signature.size(),
998 &key.front(),
999 key.size())) {
1000 ReportExtensionInstallError(extension_path,
1001 kSignatureVerificationInitFailed);
1002 return false;
1003 }
1004
1005 unsigned char buf[1 << 12];
1006 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
1007 verifier.VerifyUpdate(buf, len);
1008
1009 if (!verifier.VerifyFinal()) {
1010 ReportExtensionInstallError(extension_path, kSignatureVerificationFailed);
1011 return false;
1012 }
1013
1014 net::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()),
1015 key.size()), key_out);
1016 return true;
1017 }
1018
883 void ExtensionsServiceBackend::OnExtensionUnpacked( 1019 void ExtensionsServiceBackend::OnExtensionUnpacked(
884 const FilePath& extension_path, 1020 const FilePath& extension_path,
885 const FilePath& temp_extension_dir, 1021 const FilePath& temp_extension_dir,
886 const std::string expected_id, 1022 const std::string expected_id,
887 bool from_external, 1023 bool from_external,
888 const DictionaryValue& manifest, 1024 const DictionaryValue& manifest,
889 const std::vector< Tuple2<SkBitmap, FilePath> >& images) { 1025 const std::vector< Tuple2<SkBitmap, FilePath> >& images) {
890 Extension extension; 1026 Extension extension;
891 std::string error; 1027 std::string error;
892 if (!extension.InitFromValue(manifest, 1028 if (!extension.InitFromValue(manifest,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 error_msg += expected_id; 1071 error_msg += expected_id;
936 error_msg += ")"; 1072 error_msg += ")";
937 ReportExtensionInstallError(extension_path, error_msg); 1073 ReportExtensionInstallError(extension_path, error_msg);
938 return; 1074 return;
939 } 1075 }
940 1076
941 // <profile>/Extensions/<id> 1077 // <profile>/Extensions/<id>
942 FilePath dest_dir = install_directory_.AppendASCII(extension.id()); 1078 FilePath dest_dir = install_directory_.AppendASCII(extension.id());
943 std::string version = extension.VersionString(); 1079 std::string version = extension.VersionString();
944 std::string current_version; 1080 std::string current_version;
945 bool was_update = false; 1081 Extension::InstallType install_type =
946 if (ReadCurrentVersion(dest_dir, &current_version)) { 1082 CompareToInstalledVersion(extension.id(), version, &current_version);
947 if (!CheckCurrentVersion(version, current_version, dest_dir)) 1083
1084 // Do not allow downgrade.
1085 if (install_type == Extension::DOWNGRADE) {
1086 ReportExtensionInstallError(extension_path,
1087 "Error: Attempt to downgrade extension from more recent version.");
1088 return;
1089 }
1090
1091 if (install_type == Extension::REINSTALL) {
1092 if (NeedsReinstall(extension.id(), current_version)) {
1093 // Treat corrupted existing installation as new install case.
1094 install_type = Extension::NEW_INSTALL;
1095 } else {
1096 // The client may use this as a signal (to switch themes, for instance).
1097 ReportExtensionOverinstallAttempted(extension.id());
948 return; 1098 return;
949 was_update = true; 1099 }
950 } 1100 }
951 1101
952 // Write our parsed manifest back to disk, to ensure it doesn't contain an 1102 // Write our parsed manifest back to disk, to ensure it doesn't contain an
953 // exploitable bug that can be used to compromise the browser. 1103 // exploitable bug that can be used to compromise the browser.
954 std::string manifest_json; 1104 std::string manifest_json;
955 JSONStringValueSerializer serializer(&manifest_json); 1105 JSONStringValueSerializer serializer(&manifest_json);
956 serializer.set_pretty_print(true); 1106 serializer.set_pretty_print(true);
957 if (!serializer.Serialize(manifest)) { 1107 if (!serializer.Serialize(manifest)) {
958 ReportExtensionInstallError(extension_path, 1108 ReportExtensionInstallError(extension_path,
959 "Error serializing manifest.json."); 1109 "Error serializing manifest.json.");
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1037 // the preferences for these extensions to reflect that they've just been 1187 // the preferences for these extensions to reflect that they've just been
1038 // installed. 1188 // installed.
1039 if (!from_external) { 1189 if (!from_external) {
1040 Extension* extension = LoadExtension(version_dir, 1190 Extension* extension = LoadExtension(version_dir,
1041 location, 1191 location,
1042 true); // require id 1192 true); // require id
1043 CHECK(extension); 1193 CHECK(extension);
1044 1194
1045 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( 1195 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
1046 frontend_, &ExtensionsService::OnExtensionInstalled, extension, 1196 frontend_, &ExtensionsService::OnExtensionInstalled, extension,
1047 was_update)); 1197 install_type));
1048 1198
1049 // Only one extension, but ReportExtensionsLoaded can handle multiple, 1199 // Only one extension, but ReportExtensionsLoaded can handle multiple,
1050 // so we need to construct a list. 1200 // so we need to construct a list.
1051 scoped_ptr<ExtensionList> extensions(new ExtensionList); 1201 scoped_ptr<ExtensionList> extensions(new ExtensionList);
1052 extensions->push_back(extension); 1202 extensions->push_back(extension);
1053 LOG(INFO) << "Done."; 1203 LOG(INFO) << "Done.";
1054 // Hand off ownership of the loaded extensions to the frontend. 1204 // Hand off ownership of the loaded extensions to the frontend.
1055 ReportExtensionsLoaded(extensions.release()); 1205 ReportExtensionsLoaded(extensions.release());
1056 } else { 1206 } else {
1057 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( 1207 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
1058 frontend_, &ExtensionsService::OnExternalExtensionInstalled, 1208 frontend_, &ExtensionsService::OnExternalExtensionInstalled,
1059 extension.id(), location)); 1209 extension.id(), location));
1060 } 1210 }
1061 1211
1062 scoped_version_dir.Take(); 1212 scoped_version_dir.Take();
1063 } 1213 }
1064 1214
1065 void ExtensionsServiceBackend::ReportExtensionInstallError( 1215 void ExtensionsServiceBackend::ReportExtensionInstallError(
1066 const FilePath& extension_path, const std::string &error) { 1216 const FilePath& extension_path, const std::string &error) {
1067 1217
1068 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux. 1218 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux.
1069 std::string path_str = WideToASCII(extension_path.ToWStringHack()); 1219 std::string path_str = WideToASCII(extension_path.ToWStringHack());
1070 std::string message = 1220 std::string message =
1071 StringPrintf("Could not install extension from '%s'. %s", 1221 StringPrintf("Could not install extension from '%s'. %s",
1072 path_str.c_str(), error.c_str()); 1222 path_str.c_str(), error.c_str());
1073 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); 1223 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_);
1074 } 1224 }
1075 1225
1076 void ExtensionsServiceBackend::ReportExtensionVersionReinstalled( 1226 void ExtensionsServiceBackend::ReportExtensionOverinstallAttempted(
1077 const std::string& id) { 1227 const std::string& id) {
1078 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( 1228 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
1079 frontend_, &ExtensionsService::OnExtensionVersionReinstalled, id)); 1229 frontend_, &ExtensionsService::OnExtensionOverinstallAttempted, id));
1080 } 1230 }
1081 1231
1082 bool ExtensionsServiceBackend::ShouldSkipInstallingExtension( 1232 bool ExtensionsServiceBackend::ShouldSkipInstallingExtension(
1083 const std::set<std::string>& ids_to_ignore, 1233 const std::set<std::string>& ids_to_ignore,
1084 const std::string& id) { 1234 const std::string& id) {
1085 if (ids_to_ignore.find(id) != ids_to_ignore.end()) { 1235 if (ids_to_ignore.find(id) != ids_to_ignore.end()) {
1086 LOG(INFO) << "Skipping uninstalled external extension " << id; 1236 LOG(INFO) << "Skipping uninstalled external extension " << id;
1087 return true; 1237 return true;
1088 } 1238 }
1089 return false; 1239 return false;
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
1217 } 1367 }
1218 1368
1219 void ExtensionsServiceBackend::OnExternalExtensionFound( 1369 void ExtensionsServiceBackend::OnExternalExtensionFound(
1220 const std::string& id, const Version* version, const FilePath& path) { 1370 const std::string& id, const Version* version, const FilePath& path) {
1221 bool from_external = true; 1371 bool from_external = true;
1222 CheckVersionAndInstallExtension(id, version, path, from_external); 1372 CheckVersionAndInstallExtension(id, version, path, from_external);
1223 } 1373 }
1224 1374
1225 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, 1375 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id,
1226 const Version* version) { 1376 const Version* version) {
1227 FilePath dir(install_directory_.AppendASCII(id.c_str()));
1228 std::string current_version; 1377 std::string current_version;
1229 if (ReadCurrentVersion(dir, &current_version)) 1378 Extension::InstallType install_type =
1230 return CheckCurrentVersion(version->GetString(), current_version, dir); 1379 CompareToInstalledVersion(id, version->GetString(), &current_version);
1231 return true; 1380
1381 if (install_type == Extension::DOWNGRADE)
1382 return false;
1383
1384 return (install_type == Extension::UPGRADE ||
1385 install_type == Extension::NEW_INSTALL ||
1386 NeedsReinstall(id, current_version));
1232 } 1387 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extensions_service.h ('k') | chrome/browser/extensions/extensions_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698