blob: db66f4b2e6bd2b3e1db1eee9d1e123156211ead6 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/networking_cast_private/chrome_networking_cast_private_delegate.h"
#include <stdint.h>
#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
namespace extensions {
namespace {
const char kErrorEncryptionError[] = "Error.EncryptionError";
ChromeNetworkingCastPrivateDelegate::FactoryCallback* g_factory_callback =
nullptr;
enum class VerificationResult { SUCCESS, VERIFY_FAILURE, DECODE_FAILURE };
// Called from a blocking pool task runner. Tries to decode and verify the
// provided credentials.
VerificationResult DecodeAndVerifyCredentials(
const NetworkingCastPrivateDelegate::Credentials& credentials) {
std::string decoded_signed_data;
if (!base::Base64Decode(credentials.signed_data(), &decoded_signed_data)) {
LOG(ERROR) << "Failed to decode signed data";
return VerificationResult::DECODE_FAILURE;
}
if (networking_private_crypto::VerifyCredentials(
credentials.certificate(), credentials.intermediate_certificates(),
decoded_signed_data, credentials.unsigned_data(),
credentials.device_bssid())) {
return VerificationResult::SUCCESS;
}
return VerificationResult::VERIFY_FAILURE;
}
VerificationResult RunDecodeAndVerifyCredentials(
std::unique_ptr<NetworkingCastPrivateDelegate::Credentials> credentials) {
return DecodeAndVerifyCredentials(*credentials);
}
void VerifyDestinationCompleted(
const NetworkingCastPrivateDelegate::VerifiedCallback& success_callback,
const NetworkingCastPrivateDelegate::FailureCallback& failure_callback,
VerificationResult result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (result == VerificationResult::DECODE_FAILURE) {
failure_callback.Run(kErrorEncryptionError);
return;
}
success_callback.Run(result == VerificationResult::SUCCESS);
}
// Called from a blocking pool task runner. Returns |data| encoded using
// |credentials| on success, or an empty string on failure.
std::string RunVerifyAndEncryptData(
const std::string& data,
std::unique_ptr<NetworkingCastPrivateDelegate::Credentials> credentials) {
if (DecodeAndVerifyCredentials(*credentials) != VerificationResult::SUCCESS)
return std::string();
std::string decoded_public_key;
if (!base::Base64Decode(credentials->public_key(), &decoded_public_key)) {
LOG(ERROR) << "Failed to decode public key";
return std::string();
}
std::vector<uint8_t> public_key_data(decoded_public_key.begin(),
decoded_public_key.end());
std::vector<uint8_t> ciphertext;
if (!networking_private_crypto::EncryptByteString(public_key_data, data,
&ciphertext)) {
LOG(ERROR) << "Failed to encrypt data";
return std::string();
}
std::string base64_encoded_ciphertext;
base::Base64Encode(
base::StringPiece(reinterpret_cast<const char*>(ciphertext.data()),
ciphertext.size()),
&base64_encoded_ciphertext);
return base64_encoded_ciphertext;
}
void VerifyAndEncryptDataCompleted(
const NetworkingCastPrivateDelegate::DataCallback& success_callback,
const NetworkingCastPrivateDelegate::FailureCallback& failure_callback,
const std::string& encrypted_data) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (encrypted_data.empty())
failure_callback.Run(kErrorEncryptionError);
else
success_callback.Run(encrypted_data);
}
} // namespace
std::unique_ptr<ChromeNetworkingCastPrivateDelegate>
ChromeNetworkingCastPrivateDelegate::Create() {
if (g_factory_callback)
return g_factory_callback->Run();
return std::unique_ptr<ChromeNetworkingCastPrivateDelegate>(
new ChromeNetworkingCastPrivateDelegate);
}
void ChromeNetworkingCastPrivateDelegate::SetFactoryCallbackForTest(
FactoryCallback* factory_callback) {
g_factory_callback = factory_callback;
}
ChromeNetworkingCastPrivateDelegate::ChromeNetworkingCastPrivateDelegate() {}
ChromeNetworkingCastPrivateDelegate::~ChromeNetworkingCastPrivateDelegate() {}
void ChromeNetworkingCastPrivateDelegate::VerifyDestination(
std::unique_ptr<Credentials> credentials,
const VerifiedCallback& success_callback,
const FailureCallback& failure_callback) {
base::PostTaskAndReplyWithResult(
FROM_HERE,
{base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::Bind(&RunDecodeAndVerifyCredentials, base::Passed(&credentials)),
base::Bind(&VerifyDestinationCompleted, success_callback,
failure_callback));
}
void ChromeNetworkingCastPrivateDelegate::VerifyAndEncryptData(
const std::string& data,
std::unique_ptr<Credentials> credentials,
const DataCallback& success_callback,
const FailureCallback& failure_callback) {
base::PostTaskAndReplyWithResult(
FROM_HERE,
{base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::Bind(&RunVerifyAndEncryptData, data, base::Passed(&credentials)),
base::Bind(&VerifyAndEncryptDataCompleted, success_callback,
failure_callback));
}
} // namespace extensions