This source file includes following definitions.
- GenerateIdentityWorker
- common_name_
- Cancel
- AddCallback
- Post
- callback_
- Cancel
- OnRequestStarted
- OnRequestComplete
- backend_
- RequestIdentity
- DeleteBetween
- SetValidityPeriodForTesting
- SetTaskRunnerForTesting
- BackendFindCallback
- GenerateIdentityCallback
- PostRequestResult
- FindRequest
#include "content/browser/media/webrtc_identity_store.h"
#include <map>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/threading/worker_pool.h"
#include "content/browser/media/webrtc_identity_store_backend.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/rsa_private_key.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_util.h"
#include "url/gurl.h"
namespace content {
struct WebRTCIdentityRequestResult {
WebRTCIdentityRequestResult(int error,
const std::string& certificate,
const std::string& private_key)
: error(error), certificate(certificate), private_key(private_key) {}
int error;
std::string certificate;
std::string private_key;
};
static void GenerateIdentityWorker(const std::string& common_name,
base::TimeDelta validity_period,
WebRTCIdentityRequestResult* result) {
result->error = net::OK;
int serial_number = base::RandInt(0, std::numeric_limits<int>::max());
scoped_ptr<crypto::RSAPrivateKey> key;
base::Time now = base::Time::Now();
bool success = net::x509_util::CreateKeyAndSelfSignedCert(
"CN=" + common_name,
serial_number,
now,
now + validity_period,
&key,
&result->certificate);
if (!success) {
DLOG(ERROR) << "Unable to create x509 cert for client";
result->error = net::ERR_SELF_SIGNED_CERT_GENERATION_FAILED;
return;
}
std::vector<uint8> private_key_info;
if (!key->ExportPrivateKey(&private_key_info)) {
DLOG(ERROR) << "Unable to export private key";
result->error = net::ERR_PRIVATE_KEY_EXPORT_FAILED;
return;
}
result->private_key =
std::string(private_key_info.begin(), private_key_info.end());
}
class WebRTCIdentityRequestHandle;
class WebRTCIdentityRequest {
public:
WebRTCIdentityRequest(const GURL& origin,
const std::string& identity_name,
const std::string& common_name)
: origin_(origin),
identity_name_(identity_name),
common_name_(common_name) {}
void Cancel(WebRTCIdentityRequestHandle* handle) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (callbacks_.find(handle) == callbacks_.end())
return;
callbacks_.erase(handle);
}
private:
friend class WebRTCIdentityStore;
void AddCallback(WebRTCIdentityRequestHandle* handle,
const WebRTCIdentityStore::CompletionCallback& callback) {
DCHECK(callbacks_.find(handle) == callbacks_.end());
callbacks_[handle] = callback;
}
void Post(const WebRTCIdentityRequestResult& result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
++it)
it->second.Run(result.error, result.certificate, result.private_key);
delete this;
}
GURL origin_;
std::string identity_name_;
std::string common_name_;
typedef std::map<WebRTCIdentityRequestHandle*,
WebRTCIdentityStore::CompletionCallback> CallbackMap;
CallbackMap callbacks_;
};
class WebRTCIdentityRequestHandle {
public:
WebRTCIdentityRequestHandle(
WebRTCIdentityStore* store,
const WebRTCIdentityStore::CompletionCallback& callback)
: store_(store), request_(NULL), callback_(callback) {}
private:
friend class WebRTCIdentityStore;
void Cancel() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!request_)
return;
callback_.Reset();
WebRTCIdentityRequest* request = request_;
request_ = NULL;
request->Cancel(this);
}
void OnRequestStarted(WebRTCIdentityRequest* request) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(request);
request_ = request;
}
void OnRequestComplete(int error,
const std::string& certificate,
const std::string& private_key) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(request_);
request_ = NULL;
base::ResetAndReturn(&callback_).Run(error, certificate, private_key);
}
WebRTCIdentityStore* store_;
WebRTCIdentityRequest* request_;
WebRTCIdentityStore::CompletionCallback callback_;
DISALLOW_COPY_AND_ASSIGN(WebRTCIdentityRequestHandle);
};
WebRTCIdentityStore::WebRTCIdentityStore(const base::FilePath& path,
quota::SpecialStoragePolicy* policy)
: validity_period_(base::TimeDelta::FromDays(30)),
task_runner_(base::WorkerPool::GetTaskRunner(true)),
backend_(new WebRTCIdentityStoreBackend(path, policy, validity_period_)) {
}
WebRTCIdentityStore::~WebRTCIdentityStore() { backend_->Close(); }
base::Closure WebRTCIdentityStore::RequestIdentity(
const GURL& origin,
const std::string& identity_name,
const std::string& common_name,
const CompletionCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
WebRTCIdentityRequest* request =
FindRequest(origin, identity_name, common_name);
if (!request) {
request = new WebRTCIdentityRequest(origin, identity_name, common_name);
if (!backend_->FindIdentity(
origin,
identity_name,
common_name,
base::Bind(
&WebRTCIdentityStore::BackendFindCallback, this, request))) {
delete request;
return base::Closure();
}
in_flight_requests_.push_back(request);
}
WebRTCIdentityRequestHandle* handle =
new WebRTCIdentityRequestHandle(this, callback);
request->AddCallback(
handle,
base::Bind(&WebRTCIdentityRequestHandle::OnRequestComplete,
base::Owned(handle)));
handle->OnRequestStarted(request);
return base::Bind(&WebRTCIdentityRequestHandle::Cancel,
base::Unretained(handle));
}
void WebRTCIdentityStore::DeleteBetween(base::Time delete_begin,
base::Time delete_end,
const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
backend_->DeleteBetween(delete_begin, delete_end, callback);
}
void WebRTCIdentityStore::SetValidityPeriodForTesting(
base::TimeDelta validity_period) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
validity_period_ = validity_period;
backend_->SetValidityPeriodForTesting(validity_period);
}
void WebRTCIdentityStore::SetTaskRunnerForTesting(
const scoped_refptr<base::TaskRunner>& task_runner) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
task_runner_ = task_runner;
}
void WebRTCIdentityStore::BackendFindCallback(WebRTCIdentityRequest* request,
int error,
const std::string& certificate,
const std::string& private_key) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (error == net::OK) {
DVLOG(2) << "Identity found in DB.";
WebRTCIdentityRequestResult result(error, certificate, private_key);
PostRequestResult(request, result);
return;
}
WebRTCIdentityRequestResult* result =
new WebRTCIdentityRequestResult(0, "", "");
if (!task_runner_->PostTaskAndReply(
FROM_HERE,
base::Bind(&GenerateIdentityWorker,
request->common_name_,
validity_period_,
result),
base::Bind(&WebRTCIdentityStore::GenerateIdentityCallback,
this,
request,
base::Owned(result)))) {
WebRTCIdentityRequestResult result(net::ERR_UNEXPECTED, "", "");
PostRequestResult(request, result);
}
}
void WebRTCIdentityStore::GenerateIdentityCallback(
WebRTCIdentityRequest* request,
WebRTCIdentityRequestResult* result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (result->error == net::OK) {
DVLOG(2) << "New identity generated and added to the backend.";
backend_->AddIdentity(request->origin_,
request->identity_name_,
request->common_name_,
result->certificate,
result->private_key);
}
PostRequestResult(request, *result);
}
void WebRTCIdentityStore::PostRequestResult(
WebRTCIdentityRequest* request,
const WebRTCIdentityRequestResult& result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
for (size_t i = 0; i < in_flight_requests_.size(); ++i) {
if (in_flight_requests_[i] == request) {
in_flight_requests_.erase(in_flight_requests_.begin() + i);
break;
}
}
request->Post(result);
}
WebRTCIdentityRequest* WebRTCIdentityStore::FindRequest(
const GURL& origin,
const std::string& identity_name,
const std::string& common_name) {
for (size_t i = 0; i < in_flight_requests_.size(); ++i) {
if (in_flight_requests_[i]->origin_ == origin &&
in_flight_requests_[i]->identity_name_ == identity_name &&
in_flight_requests_[i]->common_name_ == common_name) {
return in_flight_requests_[i];
}
}
return NULL;
}
}