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

Side by Side Diff: chrome/browser/local_discovery/privetv3_session.cc

Issue 1417363004: Verify certificate of Privet v3 device (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/local_discovery/privetv3_session.h" 5 #include "chrome/browser/local_discovery/privetv3_session.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/json/json_writer.h" 8 #include "base/json/json_writer.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 26 matching lines...) Expand all
37 const char kPrivetV3KeyClientCommitment[] = "clientCommitment"; 37 const char kPrivetV3KeyClientCommitment[] = "clientCommitment";
38 const char kPrivetV3KeyCrypto[] = "crypto"; 38 const char kPrivetV3KeyCrypto[] = "crypto";
39 const char kPrivetV3KeyDeviceCommitment[] = "deviceCommitment"; 39 const char kPrivetV3KeyDeviceCommitment[] = "deviceCommitment";
40 const char kPrivetV3KeyMode[] = "mode"; 40 const char kPrivetV3KeyMode[] = "mode";
41 const char kPrivetV3KeyPairing[] = "pairing"; 41 const char kPrivetV3KeyPairing[] = "pairing";
42 const char kPrivetV3KeyRequestedScope[] = "requestedScope"; 42 const char kPrivetV3KeyRequestedScope[] = "requestedScope";
43 const char kPrivetV3KeyScope[] = "scope"; 43 const char kPrivetV3KeyScope[] = "scope";
44 const char kPrivetV3KeySessionId[] = "sessionId"; 44 const char kPrivetV3KeySessionId[] = "sessionId";
45 const char kPrivetV3KeyTokenType[] = "tokenType"; 45 const char kPrivetV3KeyTokenType[] = "tokenType";
46 46
47 const char kPrivetV3InfoHttpsPort[] = "endpoints.httpsPort";
48
47 const char kPrivetV3PairingStartPath[] = "/privet/v3/pairing/start"; 49 const char kPrivetV3PairingStartPath[] = "/privet/v3/pairing/start";
48 const char kPrivetV3PairingConfirmPath[] = "/privet/v3/pairing/confirm"; 50 const char kPrivetV3PairingConfirmPath[] = "/privet/v3/pairing/confirm";
49 const char kPrivetV3PairingCancelPath[] = "/privet/v3/pairing/cancel"; 51 const char kPrivetV3PairingCancelPath[] = "/privet/v3/pairing/cancel";
50 const char kPrivetV3AuthPath[] = "/privet/v3/auth"; 52 const char kPrivetV3AuthPath[] = "/privet/v3/auth";
51 53
52 const char kUrlPlaceHolder[] = "http://host/"; 54 const char kUrlPlaceHolder[] = "http://host/";
53 55
54 const int kUrlFetcherTimeoutSec = 30; 56 const int kUrlFetcherTimeoutSec = 60;
55 57
56 GURL CreatePrivetURL(const std::string& path) { 58 GURL CreatePrivetURL(const std::string& path) {
57 GURL url(kUrlPlaceHolder); 59 GURL url(kUrlPlaceHolder);
58 GURL::Replacements replacements; 60 GURL::Replacements replacements;
59 replacements.SetPathStr(path); 61 replacements.SetPathStr(path);
60 return url.ReplaceComponents(replacements); 62 return url.ReplaceComponents(replacements);
61 } 63 }
62 64
63 using PairingType = PrivetV3Session::PairingType; 65 using PairingType = PrivetV3Session::PairingType;
64 66
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 } 137 }
136 138
137 std::string PrivetV3Session::FetcherDelegate::GetAuthToken() { 139 std::string PrivetV3Session::FetcherDelegate::GetAuthToken() {
138 return auth_token_; 140 return auth_token_;
139 } 141 }
140 142
141 void PrivetV3Session::FetcherDelegate::OnNeedPrivetToken( 143 void PrivetV3Session::FetcherDelegate::OnNeedPrivetToken(
142 PrivetURLFetcher* fetcher, 144 PrivetURLFetcher* fetcher,
143 const PrivetURLFetcher::TokenCallback& callback) { 145 const PrivetURLFetcher::TokenCallback& callback) {
144 NOTREACHED(); 146 NOTREACHED();
145 OnError(fetcher, PrivetURLFetcher::URL_FETCH_ERROR); 147 OnError(fetcher, PrivetURLFetcher::UNKNOWN_ERROR);
146 } 148 }
147 149
148 void PrivetV3Session::FetcherDelegate::OnError( 150 void PrivetV3Session::FetcherDelegate::OnError(
149 PrivetURLFetcher* fetcher, 151 PrivetURLFetcher* fetcher,
150 PrivetURLFetcher::ErrorType error) { 152 PrivetURLFetcher::ErrorType error) {
151 LOG(ERROR) << "PrivetURLFetcher url: " << fetcher->url() 153 LOG(ERROR) << "PrivetURLFetcher url: " << fetcher->url()
152 << ", error: " << error 154 << ", error: " << error
153 << ", response code: " << fetcher->response_code(); 155 << ", response code: " << fetcher->response_code();
154 ReplyAndDestroyItself(Result::STATUS_CONNECTIONERROR, 156 ReplyAndDestroyItself(Result::STATUS_CONNECTIONERROR,
155 base::DictionaryValue()); 157 base::DictionaryValue());
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 PrivetV3Session::PrivetV3Session(scoped_ptr<PrivetHTTPClient> client) 209 PrivetV3Session::PrivetV3Session(scoped_ptr<PrivetHTTPClient> client)
208 : client_(client.Pass()), weak_ptr_factory_(this) { 210 : client_(client.Pass()), weak_ptr_factory_(this) {
209 } 211 }
210 212
211 PrivetV3Session::~PrivetV3Session() { 213 PrivetV3Session::~PrivetV3Session() {
212 Cancel(); 214 Cancel();
213 } 215 }
214 216
215 void PrivetV3Session::Init(const InitCallback& callback) { 217 void PrivetV3Session::Init(const InitCallback& callback) {
216 DCHECK(fetchers_.empty()); 218 DCHECK(fetchers_.empty());
217 DCHECK(fingerprint_.empty()); 219 DCHECK(!client_->IsInHttpsMode());
218 DCHECK(session_id_.empty()); 220 DCHECK(session_id_.empty());
219 DCHECK(privet_auth_token_.empty()); 221 DCHECK(privet_auth_token_.empty());
220 222
221 privet_auth_token_ = kPrivetV3AuthAnonymous; 223 privet_auth_token_ = kPrivetV3AuthAnonymous;
222
223 StartGetRequest(kPrivetInfoPath, 224 StartGetRequest(kPrivetInfoPath,
224 base::Bind(&PrivetV3Session::OnInfoDone, 225 base::Bind(&PrivetV3Session::OnInfoDone,
225 weak_ptr_factory_.GetWeakPtr(), callback)); 226 weak_ptr_factory_.GetWeakPtr(), callback));
226 } 227 }
227 228
228 void PrivetV3Session::OnInfoDone(const InitCallback& callback, 229 void PrivetV3Session::OnInfoDone(const InitCallback& callback,
229 Result result, 230 Result result,
230 const base::DictionaryValue& response) { 231 const base::DictionaryValue& response) {
231 if (result != Result::STATUS_SUCCESS) 232 if (result != Result::STATUS_SUCCESS)
232 return callback.Run(result, response); 233 return callback.Run(result, response);
(...skipping 14 matching lines...) Expand all
247 } 248 }
248 249
249 // The only supported crypto. 250 // The only supported crypto.
250 if (!ContainsString(*authentication, kPrivetV3KeyCrypto, 251 if (!ContainsString(*authentication, kPrivetV3KeyCrypto,
251 kPrivetV3CryptoP224Spake2) || 252 kPrivetV3CryptoP224Spake2) ||
252 !ContainsString(*authentication, kPrivetV3KeyMode, kPrivetV3KeyPairing)) { 253 !ContainsString(*authentication, kPrivetV3KeyMode, kPrivetV3KeyPairing)) {
253 LOG(ERROR) << "Response: " << response; 254 LOG(ERROR) << "Response: " << response;
254 return callback.Run(Result::STATUS_SESSIONERROR, response); 255 return callback.Run(Result::STATUS_SESSIONERROR, response);
255 } 256 }
256 257
258 int port = 0;
259 if (!response.GetInteger(kPrivetV3InfoHttpsPort, &port) || port <= 0 ||
260 port > std::numeric_limits<uint16_t>::max()) {
261 LOG(ERROR) << "Response: " << response;
262 return callback.Run(Result::STATUS_SESSIONERROR, response);
263 }
264 https_port_ = port;
265
257 callback.Run(Result::STATUS_SUCCESS, response); 266 callback.Run(Result::STATUS_SUCCESS, response);
258 } 267 }
259 268
260 void PrivetV3Session::StartPairing(PairingType pairing_type, 269 void PrivetV3Session::StartPairing(PairingType pairing_type,
261 const ResultCallback& callback) { 270 const ResultCallback& callback) {
262 base::DictionaryValue input; 271 base::DictionaryValue input;
263 input.SetString(kPrivetV3KeyPairing, 272 input.SetString(kPrivetV3KeyPairing,
264 extensions::api::gcd_private::ToString(pairing_type)); 273 extensions::api::gcd_private::ToString(pairing_type));
265 input.SetString(kPrivetV3KeyCrypto, kPrivetV3CryptoP224Spake2); 274 input.SetString(kPrivetV3KeyCrypto, kPrivetV3CryptoP224Spake2);
266 275
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 const ResultCallback& callback, 325 const ResultCallback& callback,
317 Result result, 326 Result result,
318 const base::DictionaryValue& response) { 327 const base::DictionaryValue& response) {
319 if (result != Result::STATUS_SUCCESS) 328 if (result != Result::STATUS_SUCCESS)
320 return callback.Run(result); 329 return callback.Run(result);
321 330
322 std::string fingerprint; 331 std::string fingerprint;
323 std::string signature; 332 std::string signature;
324 if (!GetDecodedString(response, kPrivetV3KeyCertFingerprint, &fingerprint) || 333 if (!GetDecodedString(response, kPrivetV3KeyCertFingerprint, &fingerprint) ||
325 !GetDecodedString(response, kPrivetV3KeyCertSignature, &signature)) { 334 !GetDecodedString(response, kPrivetV3KeyCertSignature, &signature)) {
326 LOG(ERROR) << "Response: " << response; 335 LOG(ERROR) << "Invalid response: " << response;
327 return callback.Run(Result::STATUS_SESSIONERROR); 336 return callback.Run(Result::STATUS_SESSIONERROR);
328 } 337 }
329 338
339 net::SHA256HashValue hash;
340 if (fingerprint.size() != sizeof(hash.data)) {
341 LOG(ERROR) << "Invalid fingerprint size: " << response;
342 return callback.Run(Result::STATUS_SESSIONERROR);
343 }
344 memcpy(hash.data, fingerprint.data(), sizeof(hash.data));
345
330 crypto::HMAC hmac(crypto::HMAC::SHA256); 346 crypto::HMAC hmac(crypto::HMAC::SHA256);
331 // Key will be verified below, using HMAC. 347 // Key will be verified below, using HMAC.
332 const std::string& key = spake_->GetUnverifiedKey(); 348 const std::string& key = spake_->GetUnverifiedKey();
333 if (!hmac.Init(reinterpret_cast<const unsigned char*>(key.c_str()), 349 if (!hmac.Init(reinterpret_cast<const unsigned char*>(key.c_str()),
334 key.size()) || 350 key.size()) ||
335 !hmac.Verify(fingerprint, signature)) { 351 !hmac.Verify(fingerprint, signature)) {
336 LOG(ERROR) << "Response: " << response; 352 LOG(ERROR) << "Verification failed: " << response;
337 return callback.Run(Result::STATUS_SESSIONERROR); 353 return callback.Run(Result::STATUS_BADPAIRINGCODEERROR);
338 } 354 }
339 355
340 std::string auth_code(hmac.DigestLength(), ' '); 356 std::string auth_code(hmac.DigestLength(), ' ');
341 if (!hmac.Sign(session_id_, 357 if (!hmac.Sign(session_id_,
342 reinterpret_cast<unsigned char*>(string_as_array(&auth_code)), 358 reinterpret_cast<unsigned char*>(string_as_array(&auth_code)),
343 auth_code.size())) { 359 auth_code.size())) {
344 LOG(FATAL) << "Signing failed"; 360 LOG(FATAL) << "Signing failed";
345 return callback.Run(Result::STATUS_SESSIONERROR); 361 return callback.Run(Result::STATUS_SESSIONERROR);
346 } 362 }
347 // From now this is expected certificate. 363
348 fingerprint_ = fingerprint; 364 // From now use only https with fixed certificate.
365 VLOG(1) << "Expected certificate: " << fingerprint;
366 client_->SwitchToHttps(https_port_, hash);
349 367
350 std::string auth_code_base64; 368 std::string auth_code_base64;
351 base::Base64Encode(auth_code, &auth_code_base64); 369 base::Base64Encode(auth_code, &auth_code_base64);
352 370
353 base::DictionaryValue input; 371 base::DictionaryValue input;
354 input.SetString(kPrivetV3KeyAuthCode, auth_code_base64); 372 input.SetString(kPrivetV3KeyAuthCode, auth_code_base64);
355 input.SetString(kPrivetV3KeyMode, kPrivetV3KeyPairing); 373 input.SetString(kPrivetV3KeyMode, kPrivetV3KeyPairing);
356 input.SetString(kPrivetV3KeyRequestedScope, kPrivetV3Auto); 374 input.SetString(kPrivetV3KeyRequestedScope, kPrivetV3Auto);
357 375
358 // Now we can use SendMessage with certificate validation. 376 // Now we can use SendMessage with certificate validation.
(...skipping 20 matching lines...) Expand all
379 } 397 }
380 398
381 privet_auth_token_ = token_type + " " + access_token; 399 privet_auth_token_ = token_type + " " + access_token;
382 400
383 return callback.Run(Result::STATUS_SUCCESS); 401 return callback.Run(Result::STATUS_SUCCESS);
384 } 402 }
385 403
386 void PrivetV3Session::SendMessage(const std::string& api, 404 void PrivetV3Session::SendMessage(const std::string& api,
387 const base::DictionaryValue& input, 405 const base::DictionaryValue& input,
388 const MessageCallback& callback) { 406 const MessageCallback& callback) {
389 // TODO(vitalybuka): Implement validating HTTPS certificate using 407 if (!client_->IsInHttpsMode()) {
390 // fingerprint_.
391 if (fingerprint_.empty()) {
392 LOG(ERROR) << "Session is not paired"; 408 LOG(ERROR) << "Session is not paired";
393 return callback.Run(Result::STATUS_SESSIONERROR, base::DictionaryValue()); 409 return callback.Run(Result::STATUS_SESSIONERROR, base::DictionaryValue());
394 } 410 }
395 411
396 StartPostRequest(api, input, callback); 412 StartPostRequest(api, input, callback);
397 } 413 }
398 414
399 void PrivetV3Session::RunCallback(const base::Closure& callback) { 415 void PrivetV3Session::RunCallback(const base::Closure& callback) {
400 callback.Run(); 416 callback.Run();
401 } 417 }
(...skipping 30 matching lines...) Expand all
432 return fetcher->CreateURLFetcher(CreatePrivetURL(api), request_type, 448 return fetcher->CreateURLFetcher(CreatePrivetURL(api), request_type,
433 orphaned); 449 orphaned);
434 } 450 }
435 451
436 void PrivetV3Session::DeleteFetcher(const FetcherDelegate* fetcher) { 452 void PrivetV3Session::DeleteFetcher(const FetcherDelegate* fetcher) {
437 fetchers_.erase(std::find(fetchers_.begin(), fetchers_.end(), fetcher)); 453 fetchers_.erase(std::find(fetchers_.begin(), fetchers_.end(), fetcher));
438 } 454 }
439 455
440 void PrivetV3Session::Cancel() { 456 void PrivetV3Session::Cancel() {
441 // Cancel started unconfirmed sessions. 457 // Cancel started unconfirmed sessions.
442 if (session_id_.empty() || !fingerprint_.empty()) 458 if (session_id_.empty() || client_->IsInHttpsMode())
443 return; 459 return;
444 base::DictionaryValue input; 460 base::DictionaryValue input;
445 input.SetString(kPrivetV3KeySessionId, session_id_); 461 input.SetString(kPrivetV3KeySessionId, session_id_);
446 StartPostRequest(kPrivetV3PairingCancelPath, input, MessageCallback()); 462 StartPostRequest(kPrivetV3PairingCancelPath, input, MessageCallback());
447 } 463 }
448 464
449 } // namespace local_discovery 465 } // namespace local_discovery
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698