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

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

Issue 189003004: Fix install verification for sideloaded extensions without update urls (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added comment Created 6 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/install_signer.h" 5 #include "chrome/browser/extensions/install_signer.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
(...skipping 30 matching lines...) Expand all
41 using extensions::ExtensionIdSet; 41 using extensions::ExtensionIdSet;
42 42
43 const char kExpireDateKey[] = "expire_date"; 43 const char kExpireDateKey[] = "expire_date";
44 const char kExpiryKey[] = "expiry"; 44 const char kExpiryKey[] = "expiry";
45 const char kHashKey[] = "hash"; 45 const char kHashKey[] = "hash";
46 const char kIdsKey[] = "ids"; 46 const char kIdsKey[] = "ids";
47 const char kInvalidIdsKey[] = "invalid_ids"; 47 const char kInvalidIdsKey[] = "invalid_ids";
48 const char kProtocolVersionKey[] = "protocol_version"; 48 const char kProtocolVersionKey[] = "protocol_version";
49 const char kSaltKey[] = "salt"; 49 const char kSaltKey[] = "salt";
50 const char kSignatureKey[] = "signature"; 50 const char kSignatureKey[] = "signature";
51 const char kSignatureFormatVersionKey[] = "signature_format_version";
51 const char kTimestampKey[] = "timestamp"; 52 const char kTimestampKey[] = "timestamp";
52 53
54 // This allows us to version the format of what we write into the prefs,
55 // allowing for forward migration, as well as detecting forwards/backwards
56 // incompatabilities, etc.
57 const int kSignatureFormatVersion = 2;
58
53 const size_t kSaltBytes = 32; 59 const size_t kSaltBytes = 32;
54 60
55 const char kBackendUrl[] = 61 const char kBackendUrl[] =
56 "https://www.googleapis.com/chromewebstore/v1.1/items/verify"; 62 "https://www.googleapis.com/chromewebstore/v1.1/items/verify";
57 63
58 const char kPublicKeyPEM[] = \ 64 const char kPublicKeyPEM[] = \
59 "-----BEGIN PUBLIC KEY-----" \ 65 "-----BEGIN PUBLIC KEY-----" \
60 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj/u/XDdjlDyw7gHEtaaa" \ 66 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj/u/XDdjlDyw7gHEtaaa" \
61 "sZ9GdG8WOKAyJzXd8HFrDtz2Jcuy7er7MtWvHgNDA0bwpznbI5YdZeV4UfCEsA4S" \ 67 "sZ9GdG8WOKAyJzXd8HFrDtz2Jcuy7er7MtWvHgNDA0bwpznbI5YdZeV4UfCEsA4S" \
62 "rA5b3MnWTHwA1bgbiDM+L9rrqvcadcKuOlTeN48Q0ijmhHlNFbTzvT9W0zw/GKv8" \ 68 "rA5b3MnWTHwA1bgbiDM+L9rrqvcadcKuOlTeN48Q0ijmhHlNFbTzvT9W0zw/GKv8" \
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 if (i == 4 || i == 7) { 108 if (i == 4 || i == 7) {
103 if (input[i] != '-') 109 if (input[i] != '-')
104 return false; 110 return false;
105 } else if (!IsAsciiDigit(input[i])) { 111 } else if (!IsAsciiDigit(input[i])) {
106 return false; 112 return false;
107 } 113 }
108 } 114 }
109 return true; 115 return true;
110 } 116 }
111 117
118 // Sets the value of |key| in |dictionary| to be a list with the contents of
119 // |ids|.
120 void SetExtensionIdSet(base::DictionaryValue* dictionary,
121 const char* key,
122 const ExtensionIdSet& ids) {
123 base::ListValue* id_list = new base::ListValue();
124 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i)
125 id_list->AppendString(*i);
126 dictionary->Set(key, id_list);
127 }
128
129 // Tries to fetch a list of strings from |dictionay| for |key|, and inserts
130 // them into |ids|. The return value indicates success/failure. Note: on
131 // failure, |ids| might contain partial results, for instance if some of the
132 // members of the list were not strings.
133 bool GetExtensionIdSet(const base::DictionaryValue& dictionary,
134 const char* key,
135 ExtensionIdSet* ids) {
136 const base::ListValue* id_list = NULL;
137 if (!dictionary.GetList(key, &id_list))
138 return false;
139 for (base::ListValue::const_iterator i = id_list->begin();
140 i != id_list->end();
141 ++i) {
142 std::string id;
143 if (!(*i)->GetAsString(&id)) {
144 return false;
145 }
146 ids->insert(id);
147 }
148 return true;
149 }
150
112 } // namespace 151 } // namespace
113 152
114 namespace extensions { 153 namespace extensions {
115 154
116 InstallSignature::InstallSignature() { 155 InstallSignature::InstallSignature() {
117 } 156 }
118 InstallSignature::~InstallSignature() { 157 InstallSignature::~InstallSignature() {
119 } 158 }
120 159
121 void InstallSignature::ToValue(base::DictionaryValue* value) const { 160 void InstallSignature::ToValue(base::DictionaryValue* value) const {
122 CHECK(value); 161 CHECK(value);
123 162
124 base::ListValue* id_list = new base::ListValue(); 163 value->SetInteger(kSignatureFormatVersionKey, kSignatureFormatVersion);
125 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); 164 SetExtensionIdSet(value, kIdsKey, ids);
126 ++i) 165 SetExtensionIdSet(value, kInvalidIdsKey, invalid_ids);
127 id_list->AppendString(*i);
128
129 value->Set(kIdsKey, id_list);
130 value->SetString(kExpireDateKey, expire_date); 166 value->SetString(kExpireDateKey, expire_date);
131 std::string salt_base64; 167 std::string salt_base64;
132 std::string signature_base64; 168 std::string signature_base64;
133 base::Base64Encode(salt, &salt_base64); 169 base::Base64Encode(salt, &salt_base64);
134 base::Base64Encode(signature, &signature_base64); 170 base::Base64Encode(signature, &signature_base64);
135 value->SetString(kSaltKey, salt_base64); 171 value->SetString(kSaltKey, salt_base64);
136 value->SetString(kSignatureKey, signature_base64); 172 value->SetString(kSignatureKey, signature_base64);
137 value->SetString(kTimestampKey, 173 value->SetString(kTimestampKey,
138 base::Int64ToString(timestamp.ToInternalValue())); 174 base::Int64ToString(timestamp.ToInternalValue()));
139 } 175 }
140 176
141 // static 177 // static
142 scoped_ptr<InstallSignature> InstallSignature::FromValue( 178 scoped_ptr<InstallSignature> InstallSignature::FromValue(
143 const base::DictionaryValue& value) { 179 const base::DictionaryValue& value) {
144 180
145 scoped_ptr<InstallSignature> result(new InstallSignature); 181 scoped_ptr<InstallSignature> result(new InstallSignature);
146 182
183 // For now we don't want to support any backwards compability, but in the
184 // future if we do, we would want to put the migration code here.
185 int format_version = 0;
186 if (!value.GetInteger(kSignatureFormatVersionKey, &format_version) ||
187 format_version != kSignatureFormatVersion) {
188 result.reset();
189 return result.Pass();
190 }
191
147 std::string salt_base64; 192 std::string salt_base64;
148 std::string signature_base64; 193 std::string signature_base64;
149 if (!value.GetString(kExpireDateKey, &result->expire_date) || 194 if (!value.GetString(kExpireDateKey, &result->expire_date) ||
150 !value.GetString(kSaltKey, &salt_base64) || 195 !value.GetString(kSaltKey, &salt_base64) ||
151 !value.GetString(kSignatureKey, &signature_base64) || 196 !value.GetString(kSignatureKey, &signature_base64) ||
152 !base::Base64Decode(salt_base64, &result->salt) || 197 !base::Base64Decode(salt_base64, &result->salt) ||
153 !base::Base64Decode(signature_base64, &result->signature)) { 198 !base::Base64Decode(signature_base64, &result->signature)) {
154 result.reset(); 199 result.reset();
155 return result.Pass(); 200 return result.Pass();
156 } 201 }
157 202
158 // Note: earlier versions of the code did not write out a timestamp value 203 // Note: earlier versions of the code did not write out a timestamp value
159 // so older entries will not necessarily have this. 204 // so older entries will not necessarily have this.
160 if (value.HasKey(kTimestampKey)) { 205 if (value.HasKey(kTimestampKey)) {
161 std::string timestamp; 206 std::string timestamp;
162 int64 timestamp_value = 0; 207 int64 timestamp_value = 0;
163 if (!value.GetString(kTimestampKey, &timestamp) || 208 if (!value.GetString(kTimestampKey, &timestamp) ||
164 !base::StringToInt64(timestamp, &timestamp_value)) { 209 !base::StringToInt64(timestamp, &timestamp_value)) {
165 result.reset(); 210 result.reset();
166 return result.Pass(); 211 return result.Pass();
167 } 212 }
168 result->timestamp = base::Time::FromInternalValue(timestamp_value); 213 result->timestamp = base::Time::FromInternalValue(timestamp_value);
169 } 214 }
170 215
171 const base::ListValue* ids = NULL; 216 if (!GetExtensionIdSet(value, kIdsKey, &result->ids) ||
172 if (!value.GetList(kIdsKey, &ids)) { 217 !GetExtensionIdSet(value, kInvalidIdsKey, &result->invalid_ids)) {
173 result.reset(); 218 result.reset();
174 return result.Pass(); 219 return result.Pass();
175 } 220 }
176 221
177 for (base::ListValue::const_iterator i = ids->begin(); i != ids->end(); ++i) {
178 std::string id;
179 if (!(*i)->GetAsString(&id)) {
180 result.reset();
181 return result.Pass();
182 }
183 result->ids.insert(id);
184 }
185
186 return result.Pass(); 222 return result.Pass();
187 } 223 }
188 224
189 225
190 InstallSigner::InstallSigner(net::URLRequestContextGetter* context_getter, 226 InstallSigner::InstallSigner(net::URLRequestContextGetter* context_getter,
191 const ExtensionIdSet& ids) 227 const ExtensionIdSet& ids)
192 : ids_(ids), context_getter_(context_getter) { 228 : ids_(ids), context_getter_(context_getter) {
193 } 229 }
194 230
195 InstallSigner::~InstallSigner() { 231 InstallSigner::~InstallSigner() {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 dictionary.Set(kIdsKey, id_list.release()); 389 dictionary.Set(kIdsKey, id_list.release());
354 std::string json; 390 std::string json;
355 base::JSONWriter::Write(&dictionary, &json); 391 base::JSONWriter::Write(&dictionary, &json);
356 if (json.empty()) { 392 if (json.empty()) {
357 ReportErrorViaCallback(); 393 ReportErrorViaCallback();
358 return; 394 return;
359 } 395 }
360 url_fetcher_->SetUploadData("application/json", json); 396 url_fetcher_->SetUploadData("application/json", json);
361 LogRequestStartHistograms(); 397 LogRequestStartHistograms();
362 request_start_time_ = base::Time::Now(); 398 request_start_time_ = base::Time::Now();
399 VLOG(1) << "Sending request: " << json;
363 url_fetcher_->Start(); 400 url_fetcher_->Start();
364 } 401 }
365 402
366 void InstallSigner::ReportErrorViaCallback() { 403 void InstallSigner::ReportErrorViaCallback() {
367 InstallSignature* null_signature = NULL; 404 InstallSignature* null_signature = NULL;
368 if (!callback_.is_null()) 405 if (!callback_.is_null())
369 callback_.Run(scoped_ptr<InstallSignature>(null_signature)); 406 callback_.Run(scoped_ptr<InstallSignature>(null_signature));
370 } 407 }
371 408
372 void InstallSigner::ParseFetchResponse() { 409 void InstallSigner::ParseFetchResponse() {
373 bool fetch_success = url_fetcher_->GetStatus().is_success(); 410 bool fetch_success = url_fetcher_->GetStatus().is_success();
374 UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.FetchSuccess", fetch_success); 411 UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.FetchSuccess", fetch_success);
375 412
376 std::string response; 413 std::string response;
377 if (fetch_success) { 414 if (fetch_success) {
378 if (!url_fetcher_->GetResponseAsString(&response)) 415 if (!url_fetcher_->GetResponseAsString(&response))
379 response.clear(); 416 response.clear();
380 } 417 }
381 UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.GetResponseSuccess", 418 UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.GetResponseSuccess",
382 !response.empty()); 419 !response.empty());
383 if (!fetch_success || response.empty()) { 420 if (!fetch_success || response.empty()) {
384 ReportErrorViaCallback(); 421 ReportErrorViaCallback();
385 return; 422 return;
386 } 423 }
424 VLOG(1) << "Got response: " << response;
387 425
388 // The response is JSON of the form: 426 // The response is JSON of the form:
389 // { 427 // {
390 // "protocol_version": "1", 428 // "protocol_version": "1",
391 // "signature": "<base64-encoded signature>", 429 // "signature": "<base64-encoded signature>",
392 // "expiry": "<date in YYYY-MM-DD form>", 430 // "expiry": "<date in YYYY-MM-DD form>",
393 // "invalid_ids": [ "<id3>", "<id4>" ] 431 // "invalid_ids": [ "<id3>", "<id4>" ]
394 // } 432 // }
395 // where |invalid_ids| is a list of ids from the original request that 433 // where |invalid_ids| is a list of ids from the original request that
396 // could not be verified to be in the webstore. 434 // could not be verified to be in the webstore.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 void InstallSigner::HandleSignatureResult(const std::string& signature, 482 void InstallSigner::HandleSignatureResult(const std::string& signature,
445 const std::string& expire_date, 483 const std::string& expire_date,
446 const ExtensionIdSet& invalid_ids) { 484 const ExtensionIdSet& invalid_ids) {
447 ExtensionIdSet valid_ids = 485 ExtensionIdSet valid_ids =
448 base::STLSetDifference<ExtensionIdSet>(ids_, invalid_ids); 486 base::STLSetDifference<ExtensionIdSet>(ids_, invalid_ids);
449 487
450 scoped_ptr<InstallSignature> result; 488 scoped_ptr<InstallSignature> result;
451 if (!signature.empty()) { 489 if (!signature.empty()) {
452 result.reset(new InstallSignature); 490 result.reset(new InstallSignature);
453 result->ids = valid_ids; 491 result->ids = valid_ids;
492 result->invalid_ids = invalid_ids;
454 result->salt = salt_; 493 result->salt = salt_;
455 result->signature = signature; 494 result->signature = signature;
456 result->expire_date = expire_date; 495 result->expire_date = expire_date;
457 result->timestamp = request_start_time_; 496 result->timestamp = request_start_time_;
458 bool verified = VerifySignature(*result); 497 bool verified = VerifySignature(*result);
459 UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.ResultWasValid", verified); 498 UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.ResultWasValid", verified);
460 UMA_HISTOGRAM_COUNTS_100("ExtensionInstallSigner.InvalidCount", 499 UMA_HISTOGRAM_COUNTS_100("ExtensionInstallSigner.InvalidCount",
461 invalid_ids.size()); 500 invalid_ids.size());
462 if (!verified) 501 if (!verified)
463 result.reset(); 502 result.reset();
464 } 503 }
465 504
466 if (!callback_.is_null()) 505 if (!callback_.is_null())
467 callback_.Run(result.Pass()); 506 callback_.Run(result.Pass());
468 } 507 }
469 508
470 509
471 } // namespace extensions 510 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/install_signer.h ('k') | chrome/browser/extensions/install_verifier.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698