1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/net/crl_set_fetcher.h" 6 7 #include "base/bind.h" 8 #include "base/file_util.h" 9 #include "base/path_service.h" 10 #include "base/rand_util.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/time/time.h" 13 #include "chrome/browser/component_updater/component_updater_service.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/common/chrome_constants.h" 16 #include "chrome/common/chrome_paths.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "net/cert/crl_set.h" 19 #include "net/ssl/ssl_config_service.h" 20 21 using content::BrowserThread; 22 23 CRLSetFetcher::CRLSetFetcher() : cus_(NULL) {} 24 25 bool CRLSetFetcher::GetCRLSetFilePath(base::FilePath* path) const { 26 bool ok = PathService::Get(chrome::DIR_USER_DATA, path); 27 if (!ok) { 28 NOTREACHED(); 29 return false; 30 } 31 *path = path->Append(chrome::kCRLSetFilename); 32 return true; 33 } 34 35 void CRLSetFetcher::StartInitialLoad(ComponentUpdateService* cus) { 36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 37 38 cus_ = cus; 39 40 if (!BrowserThread::PostTask( 41 BrowserThread::FILE, FROM_HERE, 42 base::Bind(&CRLSetFetcher::DoInitialLoadFromDisk, this))) { 43 NOTREACHED(); 44 } 45 } 46 47 void CRLSetFetcher::DoInitialLoadFromDisk() { 48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 49 50 base::FilePath crl_set_file_path; 51 if (!GetCRLSetFilePath(&crl_set_file_path)) 52 return; 53 54 LoadFromDisk(crl_set_file_path, &crl_set_); 55 56 uint32 sequence_of_loaded_crl = 0; 57 if (crl_set_.get()) 58 sequence_of_loaded_crl = crl_set_->sequence(); 59 60 // Get updates, advertising the sequence number of the CRL set that we just 61 // loaded, if any. 62 if (!BrowserThread::PostTask( 63 BrowserThread::UI, FROM_HERE, 64 base::Bind( 65 &CRLSetFetcher::RegisterComponent, 66 this, 67 sequence_of_loaded_crl))) { 68 NOTREACHED(); 69 } 70 } 71 72 void CRLSetFetcher::LoadFromDisk(base::FilePath path, 73 scoped_refptr<net::CRLSet>* out_crl_set) { 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 75 76 std::string crl_set_bytes; 77 if (!file_util::ReadFileToString(path, &crl_set_bytes)) 78 return; 79 80 if (!net::CRLSet::Parse(crl_set_bytes, out_crl_set)) { 81 LOG(WARNING) << "Failed to parse CRL set from " << path.MaybeAsASCII(); 82 return; 83 } 84 85 VLOG(1) << "Loaded " << crl_set_bytes.size() << " bytes of CRL set from disk"; 86 87 if (!BrowserThread::PostTask( 88 BrowserThread::IO, FROM_HERE, 89 base::Bind( 90 &CRLSetFetcher::SetCRLSetIfNewer, this, *out_crl_set))) { 91 NOTREACHED(); 92 } 93 } 94 95 void CRLSetFetcher::SetCRLSetIfNewer( 96 scoped_refptr<net::CRLSet> crl_set) { 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 98 99 scoped_refptr<net::CRLSet> old_crl_set(net::SSLConfigService::GetCRLSet()); 100 if (old_crl_set.get() && old_crl_set->sequence() > crl_set->sequence()) { 101 LOG(WARNING) << "Refusing to downgrade CRL set from #" 102 << old_crl_set->sequence() 103 << "to #" 104 << crl_set->sequence(); 105 } else { 106 net::SSLConfigService::SetCRLSet(crl_set); 107 VLOG(1) << "Installed CRL set #" << crl_set->sequence(); 108 } 109 } 110 111 // kPublicKeySHA256 is the SHA256 hash of the SubjectPublicKeyInfo of the key 112 // that's used to sign generated CRL sets. 113 static const uint8 kPublicKeySHA256[32] = { 114 0x75, 0xda, 0xf8, 0xcb, 0x77, 0x68, 0x40, 0x33, 115 0x65, 0x4c, 0x97, 0xe5, 0xc5, 0x1b, 0xcd, 0x81, 116 0x7b, 0x1e, 0xeb, 0x11, 0x2c, 0xe1, 0xa4, 0x33, 117 0x8c, 0xf5, 0x72, 0x5e, 0xed, 0xb8, 0x43, 0x97, 118 }; 119 120 void CRLSetFetcher::RegisterComponent(uint32 sequence_of_loaded_crl) { 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 122 123 CrxComponent component; 124 component.pk_hash.assign(kPublicKeySHA256, 125 kPublicKeySHA256 + sizeof(kPublicKeySHA256)); 126 component.installer = this; 127 component.name = "CRLSet"; 128 component.version = Version(base::UintToString(sequence_of_loaded_crl)); 129 if (!component.version.IsValid()) { 130 NOTREACHED(); 131 component.version = Version("0"); 132 } 133 134 if (cus_->RegisterComponent(component) != 135 ComponentUpdateService::kOk) { 136 NOTREACHED() << "RegisterComponent returned error"; 137 } 138 } 139 140 void CRLSetFetcher::OnUpdateError(int error) { 141 LOG(WARNING) << "CRLSetFetcher got error " << error 142 << " from component installer"; 143 } 144 145 bool CRLSetFetcher::Install(const base::DictionaryValue& manifest, 146 const base::FilePath& unpack_path) { 147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 148 149 base::FilePath crl_set_file_path = 150 unpack_path.Append(FILE_PATH_LITERAL("crl-set")); 151 base::FilePath save_to; 152 if (!GetCRLSetFilePath(&save_to)) 153 return true; 154 155 std::string crl_set_bytes; 156 if (!file_util::ReadFileToString(crl_set_file_path, &crl_set_bytes)) { 157 LOG(WARNING) << "Failed to find crl-set file inside CRX"; 158 return false; 159 } 160 161 bool is_delta; 162 if (!net::CRLSet::GetIsDeltaUpdate(crl_set_bytes, &is_delta)) { 163 LOG(WARNING) << "GetIsDeltaUpdate failed on CRL set from update CRX"; 164 return false; 165 } 166 167 if (!is_delta) { 168 if (!net::CRLSet::Parse(crl_set_bytes, &crl_set_)) { 169 LOG(WARNING) << "Failed to parse CRL set from update CRX"; 170 return false; 171 } 172 if (!file_util::WriteFile(save_to, crl_set_bytes.data(), 173 crl_set_bytes.size())) { 174 LOG(WARNING) << "Failed to save new CRL set to disk"; 175 // We don't return false here because we can still use this CRL set. When 176 // we restart we might revert to an older version, then we'll 177 // advertise the older version to Omaha and everything will still work. 178 } 179 } else { 180 scoped_refptr<net::CRLSet> new_crl_set; 181 if (!crl_set_->ApplyDelta(crl_set_bytes, &new_crl_set)) { 182 LOG(WARNING) << "Failed to parse delta CRL set"; 183 return false; 184 } 185 VLOG(1) << "Applied CRL set delta #" << crl_set_->sequence() 186 << "->#" << new_crl_set->sequence(); 187 const std::string new_crl_set_bytes = new_crl_set->Serialize(); 188 if (!file_util::WriteFile(save_to, new_crl_set_bytes.data(), 189 new_crl_set_bytes.size())) { 190 LOG(WARNING) << "Failed to save new CRL set to disk"; 191 // We don't return false here because we can still use this CRL set. When 192 // we restart we might revert to an older version, then we'll 193 // advertise the older version to Omaha and everything will still work. 194 } 195 crl_set_ = new_crl_set; 196 } 197 198 if (!BrowserThread::PostTask( 199 BrowserThread::IO, FROM_HERE, 200 base::Bind( 201 &CRLSetFetcher::SetCRLSetIfNewer, this, crl_set_))) { 202 NOTREACHED(); 203 } 204 205 return true; 206 } 207 208 bool CRLSetFetcher::GetInstalledFile( 209 const std::string& file, base::FilePath* installed_file) { 210 return false; 211 } 212 213 CRLSetFetcher::~CRLSetFetcher() {} 214