OLD | NEW |
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/profile.h" | 27 #include "chrome/browser/profile.h" |
26 #include "chrome/browser/utility_process_host.h" | 28 #include "chrome/browser/utility_process_host.h" |
27 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/extensions/extension.h" | 30 #include "chrome/common/extensions/extension.h" |
29 #include "chrome/common/extensions/extension_error_reporter.h" | 31 #include "chrome/common/extensions/extension_error_reporter.h" |
30 #include "chrome/common/extensions/extension_unpacker.h" | 32 #include "chrome/common/extensions/extension_unpacker.h" |
31 #include "chrome/common/json_value_serializer.h" | 33 #include "chrome/common/json_value_serializer.h" |
32 #include "chrome/common/notification_service.h" | 34 #include "chrome/common/notification_service.h" |
33 #include "chrome/common/pref_names.h" | 35 #include "chrome/common/pref_names.h" |
34 #include "chrome/common/pref_service.h" | 36 #include "chrome/common/pref_service.h" |
35 #include "chrome/common/zip.h" | 37 #include "chrome/common/zip.h" |
36 #include "chrome/common/url_constants.h" | 38 #include "chrome/common/url_constants.h" |
37 #include "grit/chromium_strings.h" | 39 #include "grit/chromium_strings.h" |
38 #include "grit/generated_resources.h" | 40 #include "grit/generated_resources.h" |
| 41 #include "net/base/base64.h" |
39 #include "third_party/skia/include/core/SkBitmap.h" | 42 #include "third_party/skia/include/core/SkBitmap.h" |
40 | 43 |
41 #if defined(OS_WIN) | 44 #if defined(OS_WIN) |
42 #include "app/win_util.h" | 45 #include "app/win_util.h" |
43 #include "base/registry.h" | 46 #include "base/registry.h" |
44 #include "base/win_util.h" | 47 #include "base/win_util.h" |
45 #endif | 48 #endif |
46 | 49 |
47 // ExtensionsService. | 50 // ExtensionsService. |
48 | 51 |
| 52 const char ExtensionsService::kExtensionHeaderMagic[] = "Cr24"; |
| 53 |
49 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; | 54 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; |
50 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; | 55 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; |
51 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL"; | 56 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL"; |
52 | 57 |
53 namespace { | 58 namespace { |
54 | 59 |
55 // A preference that keeps track of extension settings. This is a dictionary | 60 // A preference that keeps track of extension settings. This is a dictionary |
56 // object read from the Preferences file, keyed off of extension id's. | 61 // object read from the Preferences file, keyed off of extension id's. |
57 const wchar_t kExternalExtensionsPref[] = L"extensions.settings"; | 62 const wchar_t kExternalExtensionsPref[] = L"extensions.settings"; |
58 | 63 |
(...skipping 16 matching lines...) Expand all Loading... |
75 | 80 |
76 #endif | 81 #endif |
77 | 82 |
78 // A marker file to indicate that an extension was installed from an external | 83 // A marker file to indicate that an extension was installed from an external |
79 // source. | 84 // source. |
80 const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; | 85 const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; |
81 | 86 |
82 // A temporary subdirectory where we unpack extensions. | 87 // A temporary subdirectory where we unpack extensions. |
83 const char* kUnpackExtensionDir = "TEMP_UNPACK"; | 88 const char* kUnpackExtensionDir = "TEMP_UNPACK"; |
84 | 89 |
85 // The version of the extension package that this code understands. | 90 // Unpacking errors |
86 const uint32 kExpectedVersion = 1; | 91 const char* kBadMagicNumberError = "Bad magic number"; |
| 92 const char* kBadHeaderSizeError = "Excessively large key or signature"; |
| 93 const char* kBadVersionNumberError = "Bad version number"; |
| 94 const char* kInvalidExtensionHeaderError = "Invalid extension header"; |
| 95 const char* kInvalidPublicKeyError = "Invalid public key"; |
| 96 const char* kInvalidSignatureError = "Invalid signature"; |
| 97 const char* kSignatureVerificationFailed = "Signature verification failed"; |
| 98 const char* kSignatureVerificationInitFailed = |
| 99 "Signature verification initialization failed. This is most likely " |
| 100 "caused by a public key in the wrong format (should encode algorithm)."; |
87 } | 101 } |
88 | 102 |
89 // This class coordinates an extension unpack task which is run in a separate | 103 // This class coordinates an extension unpack task which is run in a separate |
90 // process. Results are sent back to this class, which we route to the | 104 // process. Results are sent back to this class, which we route to the |
91 // ExtensionServiceBackend. | 105 // ExtensionServiceBackend. |
92 class ExtensionsServiceBackend::UnpackerClient | 106 class ExtensionsServiceBackend::UnpackerClient |
93 : public UtilityProcessHost::Client { | 107 : public UtilityProcessHost::Client { |
94 public: | 108 public: |
95 UnpackerClient(ExtensionsServiceBackend* backend, | 109 UnpackerClient(ExtensionsServiceBackend* backend, |
96 const FilePath& extension_path, | 110 const FilePath& extension_path, |
| 111 const std::string& public_key, |
97 const std::string& expected_id, | 112 const std::string& expected_id, |
98 bool from_external) | 113 bool from_external) |
99 : backend_(backend), extension_path_(extension_path), | 114 : backend_(backend), extension_path_(extension_path), |
100 expected_id_(expected_id), from_external_(from_external), | 115 public_key_(public_key), expected_id_(expected_id), |
101 got_response_(false) { | 116 from_external_(from_external), got_response_(false) { |
102 } | 117 } |
103 | 118 |
104 // Starts the unpack task. We call back to the backend when the task is done, | 119 // Starts the unpack task. We call back to the backend when the task is done, |
105 // or a problem occurs. | 120 // or a problem occurs. |
106 void Start() { | 121 void Start() { |
107 AddRef(); // balanced in OnUnpackExtensionReply() | 122 AddRef(); // balanced in OnUnpackExtensionReply() |
108 | 123 |
109 // TODO(mpcomplete): handle multiple installs | 124 // TODO(mpcomplete): handle multiple installs |
110 FilePath temp_dir = backend_->install_directory_.AppendASCII( | 125 FilePath temp_dir = backend_->install_directory_.AppendASCII( |
111 kUnpackExtensionDir); | 126 kUnpackExtensionDir); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 &images)) { | 171 &images)) { |
157 OnUnpackExtensionFailed("Couldn't read image data from disk."); | 172 OnUnpackExtensionFailed("Couldn't read image data from disk."); |
158 } else { | 173 } else { |
159 OnUnpackExtensionSucceededImpl(manifest, images); | 174 OnUnpackExtensionSucceededImpl(manifest, images); |
160 } | 175 } |
161 } | 176 } |
162 | 177 |
163 void OnUnpackExtensionSucceededImpl( | 178 void OnUnpackExtensionSucceededImpl( |
164 const DictionaryValue& manifest, | 179 const DictionaryValue& manifest, |
165 const ExtensionUnpacker::DecodedImages& images) { | 180 const ExtensionUnpacker::DecodedImages& images) { |
| 181 // Add our public key into the parsed manifest. We want it to be saved so |
| 182 // that we can later refer to it (eg for generating ids, validating |
| 183 // signatures, etc). |
| 184 // The const_cast is hacky, but seems like the right thing here, rather than |
| 185 // making a full copy just to make this change. |
| 186 const_cast<DictionaryValue*>(&manifest)->SetString( |
| 187 Extension::kPublicKeyKey, public_key_); |
| 188 |
166 // The extension was unpacked to the temp dir inside our unpacking dir. | 189 // The extension was unpacked to the temp dir inside our unpacking dir. |
167 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( | 190 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( |
168 ExtensionsServiceBackend::kTempExtensionName); | 191 ExtensionsServiceBackend::kTempExtensionName); |
169 backend_->OnExtensionUnpacked(extension_path_, extension_dir, | 192 backend_->OnExtensionUnpacked(extension_path_, extension_dir, |
170 expected_id_, from_external_, | 193 expected_id_, from_external_, |
171 manifest, images); | 194 manifest, images); |
172 Cleanup(); | 195 Cleanup(); |
173 } | 196 } |
174 | 197 |
175 virtual void OnUnpackExtensionFailed(const std::string& error_message) { | 198 virtual void OnUnpackExtensionFailed(const std::string& error_message) { |
(...skipping 16 matching lines...) Expand all Loading... |
192 MessageLoop* file_loop) { | 215 MessageLoop* file_loop) { |
193 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); | 216 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); |
194 host->StartExtensionUnpacker(temp_extension_path_); | 217 host->StartExtensionUnpacker(temp_extension_path_); |
195 } | 218 } |
196 | 219 |
197 scoped_refptr<ExtensionsServiceBackend> backend_; | 220 scoped_refptr<ExtensionsServiceBackend> backend_; |
198 | 221 |
199 // The path to the crx file that we're installing. | 222 // The path to the crx file that we're installing. |
200 FilePath extension_path_; | 223 FilePath extension_path_; |
201 | 224 |
| 225 // The public key of the extension we're installing. |
| 226 std::string public_key_; |
| 227 |
202 // The path to the copy of the crx file in the temporary directory where we're | 228 // The path to the copy of the crx file in the temporary directory where we're |
203 // unpacking it. | 229 // unpacking it. |
204 FilePath temp_extension_path_; | 230 FilePath temp_extension_path_; |
205 | 231 |
206 // The ID we expect this extension to have, if any. | 232 // The ID we expect this extension to have, if any. |
207 std::string expected_id_; | 233 std::string expected_id_; |
208 | 234 |
209 // True if this is being installed from an external source. | 235 // True if this is being installed from an external source. |
210 bool from_external_; | 236 bool from_external_; |
211 | 237 |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 | 392 |
367 NotificationService::current()->Notify( | 393 NotificationService::current()->Notify( |
368 NotificationType::EXTENSIONS_LOADED, | 394 NotificationType::EXTENSIONS_LOADED, |
369 NotificationService::AllSources(), | 395 NotificationService::AllSources(), |
370 Details<ExtensionList>(&enabled_extensions)); | 396 Details<ExtensionList>(&enabled_extensions)); |
371 | 397 |
372 delete new_extensions; | 398 delete new_extensions; |
373 } | 399 } |
374 | 400 |
375 void ExtensionsService::OnExtensionInstalled(Extension* extension, | 401 void ExtensionsService::OnExtensionInstalled(Extension* extension, |
376 bool update) { | 402 Extension::InstallType install_type) { |
377 UpdateExtensionPref(ASCIIToWide(extension->id()), kState, | 403 UpdateExtensionPref(ASCIIToWide(extension->id()), kState, |
378 Value::CreateIntegerValue(Extension::ENABLED), false); | 404 Value::CreateIntegerValue(Extension::ENABLED), false); |
379 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation, | 405 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation, |
380 Value::CreateIntegerValue(Extension::INTERNAL), true); | 406 Value::CreateIntegerValue(Extension::INTERNAL), true); |
381 | 407 |
382 // If the extension is a theme, tell the profile (and therefore ThemeProvider) | 408 // If the extension is a theme, tell the profile (and therefore ThemeProvider) |
383 // to apply it. | 409 // to apply it. |
384 if (extension->IsTheme()) { | 410 if (extension->IsTheme()) { |
385 NotificationService::current()->Notify( | 411 NotificationService::current()->Notify( |
386 NotificationType::THEME_INSTALLED, | 412 NotificationType::THEME_INSTALLED, |
387 NotificationService::AllSources(), | 413 NotificationService::AllSources(), |
388 Details<Extension>(extension)); | 414 Details<Extension>(extension)); |
389 } else { | 415 } else { |
390 NotificationService::current()->Notify( | 416 NotificationService::current()->Notify( |
391 NotificationType::EXTENSION_INSTALLED, | 417 NotificationType::EXTENSION_INSTALLED, |
392 NotificationService::AllSources(), | 418 NotificationService::AllSources(), |
393 Details<Extension>(extension)); | 419 Details<Extension>(extension)); |
394 } | 420 } |
395 } | 421 } |
396 | 422 |
397 void ExtensionsService::OnExternalExtensionInstalled( | 423 void ExtensionsService::OnExternalExtensionInstalled( |
398 const std::string& id, Extension::Location location) { | 424 const std::string& id, Extension::Location location) { |
399 DCHECK(Extension::IsExternalLocation(location)); | 425 DCHECK(Extension::IsExternalLocation(location)); |
400 UpdateExtensionPref(ASCIIToWide(id), kState, | 426 UpdateExtensionPref(ASCIIToWide(id), kState, |
401 Value::CreateIntegerValue(Extension::ENABLED), false); | 427 Value::CreateIntegerValue(Extension::ENABLED), false); |
402 UpdateExtensionPref(ASCIIToWide(id), kLocation, | 428 UpdateExtensionPref(ASCIIToWide(id), kLocation, |
403 Value::CreateIntegerValue(location), true); | 429 Value::CreateIntegerValue(location), true); |
404 } | 430 } |
405 | 431 |
406 void ExtensionsService::OnExtensionVersionReinstalled(const std::string& id) { | 432 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) { |
407 Extension* extension = GetExtensionByID(id); | 433 Extension* extension = GetExtensionByID(id); |
408 if (extension && extension->IsTheme()) { | 434 if (extension && extension->IsTheme()) { |
409 NotificationService::current()->Notify( | 435 NotificationService::current()->Notify( |
410 NotificationType::THEME_INSTALLED, | 436 NotificationType::THEME_INSTALLED, |
411 NotificationService::AllSources(), | 437 NotificationService::AllSources(), |
412 Details<Extension>(extension)); | 438 Details<Extension>(extension)); |
413 } | 439 } |
414 } | 440 } |
415 | 441 |
416 Extension* ExtensionsService::GetExtensionByID(std::string id) { | 442 Extension* ExtensionsService::GetExtensionByID(std::string id) { |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 Extension* extension = LoadExtension(extension_path, | 643 Extension* extension = LoadExtension(extension_path, |
618 false); // don't require ID | 644 false); // don't require ID |
619 if (extension) { | 645 if (extension) { |
620 extension->set_location(Extension::LOAD); | 646 extension->set_location(Extension::LOAD); |
621 ExtensionList* extensions = new ExtensionList; | 647 ExtensionList* extensions = new ExtensionList; |
622 extensions->push_back(extension); | 648 extensions->push_back(extension); |
623 ReportExtensionsLoaded(extensions); | 649 ReportExtensionsLoaded(extensions); |
624 } | 650 } |
625 } | 651 } |
626 | 652 |
| 653 DictionaryValue* ExtensionsServiceBackend::ReadManifest(FilePath manifest_path, |
| 654 std::string* error) { |
| 655 JSONFileValueSerializer serializer(manifest_path); |
| 656 scoped_ptr<Value> root(serializer.Deserialize(error)); |
| 657 if (!root.get()) |
| 658 return NULL; |
| 659 |
| 660 if (!root->IsType(Value::TYPE_DICTIONARY)) { |
| 661 *error = Extension::kInvalidManifestError; |
| 662 return NULL; |
| 663 } |
| 664 |
| 665 return static_cast<DictionaryValue*>(root.release()); |
| 666 } |
| 667 |
627 Extension* ExtensionsServiceBackend::LoadExtension( | 668 Extension* ExtensionsServiceBackend::LoadExtension( |
628 const FilePath& extension_path, bool require_id) { | 669 const FilePath& extension_path, bool require_id) { |
629 FilePath manifest_path = | 670 FilePath manifest_path = |
630 extension_path.AppendASCII(Extension::kManifestFilename); | 671 extension_path.AppendASCII(Extension::kManifestFilename); |
631 if (!file_util::PathExists(manifest_path)) { | 672 if (!file_util::PathExists(manifest_path)) { |
632 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); | 673 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); |
633 return NULL; | 674 return NULL; |
634 } | 675 } |
635 | 676 |
636 JSONFileValueSerializer serializer(manifest_path); | |
637 std::string error; | 677 std::string error; |
638 scoped_ptr<Value> root(serializer.Deserialize(&error)); | 678 scoped_ptr<DictionaryValue> root(ReadManifest(manifest_path, &error)); |
639 if (!root.get()) { | 679 if (!root.get()) { |
640 ReportExtensionLoadError(extension_path, error); | 680 ReportExtensionLoadError(extension_path, error); |
641 return NULL; | 681 return NULL; |
642 } | 682 } |
643 | 683 |
644 if (!root->IsType(Value::TYPE_DICTIONARY)) { | |
645 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); | |
646 return NULL; | |
647 } | |
648 | |
649 scoped_ptr<Extension> extension(new Extension(extension_path)); | 684 scoped_ptr<Extension> extension(new Extension(extension_path)); |
650 if (!extension->InitFromValue(*static_cast<DictionaryValue*>(root.get()), | 685 if (!extension->InitFromValue(*root.get(), require_id, &error)) { |
651 require_id, &error)) { | |
652 ReportExtensionLoadError(extension_path, error); | 686 ReportExtensionLoadError(extension_path, error); |
653 return NULL; | 687 return NULL; |
654 } | 688 } |
655 | 689 |
656 FilePath external_marker = extension_path.AppendASCII(kExternalInstallFile); | 690 FilePath external_marker = extension_path.AppendASCII(kExternalInstallFile); |
657 if (file_util::PathExists(external_marker)) { | 691 if (file_util::PathExists(external_marker)) { |
658 extension->set_location( | 692 extension->set_location( |
659 extension->ExternalExtensionInstallType(registry_path_)); | 693 extension->ExternalExtensionInstallType(registry_path_)); |
660 } else { | 694 } else { |
661 extension->set_location(Extension::INTERNAL); | 695 extension->set_location(Extension::INTERNAL); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName); | 790 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName); |
757 if (file_util::PathExists(current_version)) { | 791 if (file_util::PathExists(current_version)) { |
758 if (file_util::ReadFileToString(current_version, version_string)) { | 792 if (file_util::ReadFileToString(current_version, version_string)) { |
759 TrimWhitespace(*version_string, TRIM_ALL, version_string); | 793 TrimWhitespace(*version_string, TRIM_ALL, version_string); |
760 return true; | 794 return true; |
761 } | 795 } |
762 } | 796 } |
763 return false; | 797 return false; |
764 } | 798 } |
765 | 799 |
766 bool ExtensionsServiceBackend::CheckCurrentVersion( | 800 Extension::InstallType ExtensionsServiceBackend::CompareToInstalledVersion( |
| 801 const std::string& id, |
767 const std::string& new_version_str, | 802 const std::string& new_version_str, |
768 const std::string& current_version_str, | 803 std::string *current_version_str) { |
769 const FilePath& dest_dir) { | 804 CHECK(current_version_str); |
| 805 FilePath dir(install_directory_.AppendASCII(id.c_str())); |
| 806 if (!ReadCurrentVersion(dir, current_version_str)) |
| 807 return Extension::NEW_INSTALL; |
| 808 |
770 scoped_ptr<Version> current_version( | 809 scoped_ptr<Version> current_version( |
771 Version::GetVersionFromString(current_version_str)); | 810 Version::GetVersionFromString(*current_version_str)); |
772 scoped_ptr<Version> new_version( | 811 scoped_ptr<Version> new_version( |
773 Version::GetVersionFromString(new_version_str)); | 812 Version::GetVersionFromString(new_version_str)); |
774 if (current_version->CompareTo(*new_version) >= 0) { | 813 int comp = new_version->CompareTo(*current_version); |
775 // Verify that the directory actually exists. If it doesn't we'll return | 814 if (comp > 0) |
776 // true so that the install code will repair the broken installation. | 815 return Extension::UPGRADE; |
777 // TODO(erikkay): A further step would be to verify that the extension | 816 else if (comp == 0) |
778 // has actually loaded successfully. | 817 return Extension::REINSTALL; |
779 FilePath version_dir = dest_dir.AppendASCII(current_version_str); | 818 else |
780 if (file_util::PathExists(version_dir)) { | 819 return Extension::DOWNGRADE; |
781 std::string id = WideToASCII(dest_dir.BaseName().ToWStringHack()); | 820 } |
782 StringToLowerASCII(&id); | 821 |
783 ReportExtensionVersionReinstalled(id); | 822 bool ExtensionsServiceBackend::NeedsReinstall(const std::string& id, |
784 return false; | 823 const std::string& current_version) { |
785 } | 824 // Verify that the directory actually exists. |
786 } | 825 // TODO(erikkay): A further step would be to verify that the extension |
787 return true; | 826 // has actually loaded successfully. |
| 827 FilePath dir(install_directory_.AppendASCII(id.c_str())); |
| 828 FilePath version_dir(dir.AppendASCII(current_version)); |
| 829 return !file_util::PathExists(version_dir); |
788 } | 830 } |
789 | 831 |
790 bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir, | 832 bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir, |
791 const FilePath& dest_dir) { | 833 const FilePath& dest_dir) { |
792 if (file_util::PathExists(dest_dir)) { | 834 if (file_util::PathExists(dest_dir)) { |
793 // By the time we get here, it should be safe to assume that this directory | 835 // By the time we get here, it should be safe to assume that this directory |
794 // is not currently in use (it's not the current active version). | 836 // is not currently in use (it's not the current active version). |
795 if (!file_util::Delete(dest_dir, true)) { | 837 if (!file_util::Delete(dest_dir, true)) { |
796 ReportExtensionInstallError(source_dir, | 838 ReportExtensionInstallError(source_dir, |
797 "Can't delete existing version directory."); | 839 "Can't delete existing version directory."); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 LOG(INFO) << "Installing extension " << extension_path.value(); | 906 LOG(INFO) << "Installing extension " << extension_path.value(); |
865 | 907 |
866 frontend_ = frontend; | 908 frontend_ = frontend; |
867 alert_on_error_ = true; | 909 alert_on_error_ = true; |
868 | 910 |
869 bool from_external = false; | 911 bool from_external = false; |
870 InstallOrUpdateExtension(extension_path, std::string(), from_external); | 912 InstallOrUpdateExtension(extension_path, std::string(), from_external); |
871 } | 913 } |
872 | 914 |
873 void ExtensionsServiceBackend::InstallOrUpdateExtension( | 915 void ExtensionsServiceBackend::InstallOrUpdateExtension( |
874 const FilePath& extension_path, const std::string& expected_id, | 916 const FilePath& extension_path, |
| 917 const std::string& expected_id, |
875 bool from_external) { | 918 bool from_external) { |
876 UnpackerClient* client = | 919 std::string actual_public_key; |
877 new UnpackerClient(this, extension_path, expected_id, from_external); | 920 if (!ValidateSignature(extension_path, &actual_public_key)) |
| 921 return; // Failures reported within ValidateSignature(). |
| 922 |
| 923 UnpackerClient* client = new UnpackerClient( |
| 924 this, extension_path, actual_public_key, expected_id, from_external); |
878 client->Start(); | 925 client->Start(); |
879 } | 926 } |
880 | 927 |
| 928 bool ExtensionsServiceBackend::ValidateSignature(const FilePath& extension_path, |
| 929 std::string* key_out) { |
| 930 ScopedStdioHandle file(file_util::OpenFile(extension_path, "rb")); |
| 931 if (!file.get()) { |
| 932 ReportExtensionInstallError(extension_path, "Could not open file."); |
| 933 return NULL; |
| 934 } |
| 935 |
| 936 // Read and verify the header. |
| 937 ExtensionsService::ExtensionHeader header; |
| 938 size_t len; |
| 939 |
| 940 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it |
| 941 // appears that we don't have any endian/alignment aware serialization |
| 942 // code in the code base. So for now, this assumes that we're running |
| 943 // on a little endian machine with 4 byte alignment. |
| 944 len = fread(&header, 1, sizeof(ExtensionsService::ExtensionHeader), |
| 945 file.get()); |
| 946 if (len < sizeof(ExtensionsService::ExtensionHeader)) { |
| 947 ReportExtensionInstallError(extension_path, kInvalidExtensionHeaderError); |
| 948 return false; |
| 949 } |
| 950 if (strncmp(ExtensionsService::kExtensionHeaderMagic, header.magic, |
| 951 sizeof(header.magic))) { |
| 952 ReportExtensionInstallError(extension_path, kBadMagicNumberError); |
| 953 return false; |
| 954 } |
| 955 if (header.version != ExtensionsService::kCurrentVersion) { |
| 956 ReportExtensionInstallError(extension_path, kBadVersionNumberError); |
| 957 return false; |
| 958 } |
| 959 if (header.key_size > ExtensionsService::kMaxPublicKeySize || |
| 960 header.signature_size > ExtensionsService::kMaxSignatureSize) { |
| 961 ReportExtensionInstallError(extension_path, kBadHeaderSizeError); |
| 962 return false; |
| 963 } |
| 964 |
| 965 std::vector<uint8> key; |
| 966 key.resize(header.key_size); |
| 967 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); |
| 968 if (len < header.key_size) { |
| 969 ReportExtensionInstallError(extension_path, kInvalidPublicKeyError); |
| 970 return false; |
| 971 } |
| 972 |
| 973 std::vector<uint8> signature; |
| 974 signature.resize(header.signature_size); |
| 975 len = fread(&signature.front(), sizeof(uint8), header.signature_size, |
| 976 file.get()); |
| 977 if (len < header.signature_size) { |
| 978 ReportExtensionInstallError(extension_path, kInvalidSignatureError); |
| 979 return false; |
| 980 } |
| 981 |
| 982 // Note: this structure is an ASN.1 which encodes the algorithm used |
| 983 // with its parameters. This is defined in PKCS #1 v2.1 (RFC 3447). |
| 984 // It is encoding: { OID sha1WithRSAEncryption PARAMETERS NULL } |
| 985 // TODO(aa): This needs to be factored away someplace common. |
| 986 const uint8 signature_algorithm[15] = { |
| 987 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, |
| 988 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 |
| 989 }; |
| 990 |
| 991 base::SignatureVerifier verifier; |
| 992 if (!verifier.VerifyInit(signature_algorithm, |
| 993 sizeof(signature_algorithm), |
| 994 &signature.front(), |
| 995 signature.size(), |
| 996 &key.front(), |
| 997 key.size())) { |
| 998 ReportExtensionInstallError(extension_path, |
| 999 kSignatureVerificationInitFailed); |
| 1000 return false; |
| 1001 } |
| 1002 |
| 1003 unsigned char buf[1 << 12]; |
| 1004 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) |
| 1005 verifier.VerifyUpdate(buf, len); |
| 1006 |
| 1007 if (!verifier.VerifyFinal()) { |
| 1008 ReportExtensionInstallError(extension_path, kSignatureVerificationFailed); |
| 1009 return false; |
| 1010 } |
| 1011 |
| 1012 net::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), |
| 1013 key.size()), key_out); |
| 1014 return true; |
| 1015 } |
| 1016 |
881 void ExtensionsServiceBackend::OnExtensionUnpacked( | 1017 void ExtensionsServiceBackend::OnExtensionUnpacked( |
882 const FilePath& extension_path, | 1018 const FilePath& extension_path, |
883 const FilePath& temp_extension_dir, | 1019 const FilePath& temp_extension_dir, |
884 const std::string expected_id, | 1020 const std::string expected_id, |
885 bool from_external, | 1021 bool from_external, |
886 const DictionaryValue& manifest, | 1022 const DictionaryValue& manifest, |
887 const std::vector< Tuple2<SkBitmap, FilePath> >& images) { | 1023 const std::vector< Tuple2<SkBitmap, FilePath> >& images) { |
888 Extension extension; | 1024 Extension extension; |
889 std::string error; | 1025 std::string error; |
890 if (!extension.InitFromValue(manifest, | 1026 if (!extension.InitFromValue(manifest, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 error_msg += expected_id; | 1069 error_msg += expected_id; |
934 error_msg += ")"; | 1070 error_msg += ")"; |
935 ReportExtensionInstallError(extension_path, error_msg); | 1071 ReportExtensionInstallError(extension_path, error_msg); |
936 return; | 1072 return; |
937 } | 1073 } |
938 | 1074 |
939 // <profile>/Extensions/<id> | 1075 // <profile>/Extensions/<id> |
940 FilePath dest_dir = install_directory_.AppendASCII(extension.id()); | 1076 FilePath dest_dir = install_directory_.AppendASCII(extension.id()); |
941 std::string version = extension.VersionString(); | 1077 std::string version = extension.VersionString(); |
942 std::string current_version; | 1078 std::string current_version; |
943 bool was_update = false; | 1079 Extension::InstallType install_type = |
944 if (ReadCurrentVersion(dest_dir, ¤t_version)) { | 1080 CompareToInstalledVersion(extension.id(), version, ¤t_version); |
945 if (!CheckCurrentVersion(version, current_version, dest_dir)) | 1081 |
| 1082 // Do not allow downgrade. |
| 1083 if (install_type == Extension::DOWNGRADE) { |
| 1084 ReportExtensionInstallError(extension_path, |
| 1085 "Error: Attempt to downgrade extension from more recent version."); |
| 1086 return; |
| 1087 } |
| 1088 |
| 1089 if (install_type == Extension::REINSTALL) { |
| 1090 if (NeedsReinstall(extension.id(), current_version)) { |
| 1091 // Treat corrupted existing installation as new install case. |
| 1092 install_type = Extension::NEW_INSTALL; |
| 1093 } else { |
| 1094 // The client may use this as a signal (to switch themes, for instance). |
| 1095 ReportExtensionOverinstallAttempted(extension.id()); |
946 return; | 1096 return; |
947 was_update = true; | 1097 } |
948 } | 1098 } |
949 | 1099 |
950 // Write our parsed manifest back to disk, to ensure it doesn't contain an | 1100 // Write our parsed manifest back to disk, to ensure it doesn't contain an |
951 // exploitable bug that can be used to compromise the browser. | 1101 // exploitable bug that can be used to compromise the browser. |
952 std::string manifest_json; | 1102 std::string manifest_json; |
953 JSONStringValueSerializer serializer(&manifest_json); | 1103 JSONStringValueSerializer serializer(&manifest_json); |
954 serializer.set_pretty_print(true); | 1104 serializer.set_pretty_print(true); |
955 if (!serializer.Serialize(manifest)) { | 1105 if (!serializer.Serialize(manifest)) { |
956 ReportExtensionInstallError(extension_path, | 1106 ReportExtensionInstallError(extension_path, |
957 "Error serializing manifest.json."); | 1107 "Error serializing manifest.json."); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1036 // occurs before the normal startup so we just let startup pick them up. We | 1186 // occurs before the normal startup so we just let startup pick them up. We |
1037 // notify on installation of external extensions because we need to update | 1187 // notify on installation of external extensions because we need to update |
1038 // the preferences for these extensions to reflect that they've just been | 1188 // the preferences for these extensions to reflect that they've just been |
1039 // installed. | 1189 // installed. |
1040 if (!from_external) { | 1190 if (!from_external) { |
1041 Extension* extension = LoadExtension(version_dir, true); // require id | 1191 Extension* extension = LoadExtension(version_dir, true); // require id |
1042 CHECK(extension); | 1192 CHECK(extension); |
1043 | 1193 |
1044 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 1194 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
1045 frontend_, &ExtensionsService::OnExtensionInstalled, extension, | 1195 frontend_, &ExtensionsService::OnExtensionInstalled, extension, |
1046 was_update)); | 1196 install_type)); |
1047 | 1197 |
1048 // Only one extension, but ReportExtensionsLoaded can handle multiple, | 1198 // Only one extension, but ReportExtensionsLoaded can handle multiple, |
1049 // so we need to construct a list. | 1199 // so we need to construct a list. |
1050 scoped_ptr<ExtensionList> extensions(new ExtensionList); | 1200 scoped_ptr<ExtensionList> extensions(new ExtensionList); |
1051 extensions->push_back(extension); | 1201 extensions->push_back(extension); |
1052 LOG(INFO) << "Done."; | 1202 LOG(INFO) << "Done."; |
1053 // Hand off ownership of the loaded extensions to the frontend. | 1203 // Hand off ownership of the loaded extensions to the frontend. |
1054 ReportExtensionsLoaded(extensions.release()); | 1204 ReportExtensionsLoaded(extensions.release()); |
1055 } else { | 1205 } else { |
1056 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 1206 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
1057 frontend_, &ExtensionsService::OnExternalExtensionInstalled, | 1207 frontend_, &ExtensionsService::OnExternalExtensionInstalled, |
1058 extension.id(), | 1208 extension.id(), |
1059 extension.ExternalExtensionInstallType(registry_path_))); | 1209 extension.ExternalExtensionInstallType(registry_path_))); |
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 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1255 // not a big deal though, because we'll notice next time we startup that the | 1405 // not a big deal though, because we'll notice next time we startup that the |
1256 // Current Version file is gone and finish the delete then. | 1406 // Current Version file is gone and finish the delete then. |
1257 if (!file_util::Delete(extension_directory, true)) { | 1407 if (!file_util::Delete(extension_directory, true)) { |
1258 LOG(WARNING) << "Could not delete directory for extension " | 1408 LOG(WARNING) << "Could not delete directory for extension " |
1259 << extension_id; | 1409 << extension_id; |
1260 } | 1410 } |
1261 } | 1411 } |
1262 | 1412 |
1263 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, | 1413 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, |
1264 const std::string& version) { | 1414 const std::string& version) { |
1265 FilePath dir(install_directory_.AppendASCII(id.c_str())); | |
1266 std::string current_version; | 1415 std::string current_version; |
1267 if (ReadCurrentVersion(dir, ¤t_version)) { | 1416 Extension::InstallType install_type = CompareToInstalledVersion(id, version, |
1268 return CheckCurrentVersion(version, current_version, dir); | 1417 ¤t_version); |
1269 } | 1418 |
1270 return true; | 1419 if (install_type == Extension::DOWNGRADE) |
| 1420 return false; |
| 1421 |
| 1422 return (install_type == Extension::UPGRADE || |
| 1423 install_type == Extension::NEW_INSTALL || |
| 1424 NeedsReinstall(id, current_version)); |
1271 } | 1425 } |
OLD | NEW |