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/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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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, ¤t_version)) { | 1082 CompareToInstalledVersion(extension.id(), version, ¤t_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 Loading... |
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 Loading... |
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, ¤t_version)) | 1378 Extension::InstallType install_type = |
1230 return CheckCurrentVersion(version->GetString(), current_version, dir); | 1379 CompareToInstalledVersion(id, version->GetString(), ¤t_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 } |
OLD | NEW |