mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
224 lines
6.9 KiB
C++
224 lines
6.9 KiB
C++
|
// Copyright 2014 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 "net/quic/crypto/channel_id_chromium.h"
|
||
|
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "base/strings/string_util.h"
|
||
|
#include "crypto/ec_private_key.h"
|
||
|
#include "crypto/ec_signature_creator.h"
|
||
|
#include "net/base/net_errors.h"
|
||
|
#include "net/cert/asn1_util.h"
|
||
|
#include "net/ssl/channel_id_service.h"
|
||
|
|
||
|
namespace net {
|
||
|
|
||
|
ChannelIDKeyChromium::ChannelIDKeyChromium(
|
||
|
std::unique_ptr<crypto::ECPrivateKey> ec_private_key)
|
||
|
: ec_private_key_(std::move(ec_private_key)) {}
|
||
|
|
||
|
ChannelIDKeyChromium::~ChannelIDKeyChromium() {}
|
||
|
|
||
|
bool ChannelIDKeyChromium::Sign(quic::QuicStringPiece signed_data,
|
||
|
std::string* out_signature) const {
|
||
|
std::unique_ptr<crypto::ECSignatureCreator> sig_creator(
|
||
|
crypto::ECSignatureCreator::Create(ec_private_key_.get()));
|
||
|
if (!sig_creator) {
|
||
|
return false;
|
||
|
}
|
||
|
const size_t len1 = strlen(quic::ChannelIDVerifier::kContextStr) + 1;
|
||
|
const size_t len2 = strlen(quic::ChannelIDVerifier::kClientToServerStr) + 1;
|
||
|
std::vector<uint8_t> data(len1 + len2 + signed_data.size());
|
||
|
memcpy(&data[0], quic::ChannelIDVerifier::kContextStr, len1);
|
||
|
memcpy(&data[len1], quic::ChannelIDVerifier::kClientToServerStr, len2);
|
||
|
memcpy(&data[len1 + len2], signed_data.data(), signed_data.size());
|
||
|
std::vector<uint8_t> der_signature;
|
||
|
if (!sig_creator->Sign(&data[0], data.size(), &der_signature)) {
|
||
|
return false;
|
||
|
}
|
||
|
std::vector<uint8_t> raw_signature;
|
||
|
if (!sig_creator->DecodeSignature(der_signature, &raw_signature)) {
|
||
|
return false;
|
||
|
}
|
||
|
memcpy(base::WriteInto(out_signature, raw_signature.size() + 1),
|
||
|
&raw_signature[0], raw_signature.size());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::string ChannelIDKeyChromium::SerializeKey() const {
|
||
|
std::string out_key;
|
||
|
if (!ec_private_key_->ExportRawPublicKey(&out_key)) {
|
||
|
return std::string();
|
||
|
}
|
||
|
return out_key;
|
||
|
}
|
||
|
|
||
|
// A Job handles the lookup of a single channel ID. It is owned by the
|
||
|
// quic::ChannelIDSource. If the operation can not complete synchronously, it
|
||
|
// will notify the quic::ChannelIDSource upon completion.
|
||
|
class ChannelIDSourceChromium::Job {
|
||
|
public:
|
||
|
Job(ChannelIDSourceChromium* channel_id_source,
|
||
|
ChannelIDService* channel_id_service);
|
||
|
|
||
|
// Starts the channel ID lookup. If |quic::QUIC_PENDING| is returned, then
|
||
|
// |callback| will be invoked asynchronously when the operation completes.
|
||
|
quic::QuicAsyncStatus GetChannelIDKey(
|
||
|
const std::string& hostname,
|
||
|
std::unique_ptr<quic::ChannelIDKey>* channel_id_key,
|
||
|
quic::ChannelIDSourceCallback* callback);
|
||
|
|
||
|
private:
|
||
|
enum State {
|
||
|
STATE_NONE,
|
||
|
STATE_GET_CHANNEL_ID_KEY,
|
||
|
STATE_GET_CHANNEL_ID_KEY_COMPLETE,
|
||
|
};
|
||
|
|
||
|
int DoLoop(int last_io_result);
|
||
|
void OnIOComplete(int result);
|
||
|
int DoGetChannelIDKey(int result);
|
||
|
int DoGetChannelIDKeyComplete(int result);
|
||
|
|
||
|
// Channel ID source to notify when this jobs completes.
|
||
|
ChannelIDSourceChromium* const channel_id_source_;
|
||
|
|
||
|
ChannelIDService* const channel_id_service_;
|
||
|
|
||
|
std::unique_ptr<crypto::ECPrivateKey> channel_id_crypto_key_;
|
||
|
ChannelIDService::Request channel_id_request_;
|
||
|
|
||
|
// |hostname| specifies the hostname for which we need a channel ID.
|
||
|
std::string hostname_;
|
||
|
|
||
|
std::unique_ptr<quic::ChannelIDSourceCallback> callback_;
|
||
|
|
||
|
std::unique_ptr<quic::ChannelIDKey> channel_id_key_;
|
||
|
|
||
|
State next_state_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(Job);
|
||
|
};
|
||
|
|
||
|
ChannelIDSourceChromium::Job::Job(ChannelIDSourceChromium* channel_id_source,
|
||
|
ChannelIDService* channel_id_service)
|
||
|
: channel_id_source_(channel_id_source),
|
||
|
channel_id_service_(channel_id_service),
|
||
|
next_state_(STATE_NONE) {}
|
||
|
|
||
|
quic::QuicAsyncStatus ChannelIDSourceChromium::Job::GetChannelIDKey(
|
||
|
const std::string& hostname,
|
||
|
std::unique_ptr<quic::ChannelIDKey>* channel_id_key,
|
||
|
quic::ChannelIDSourceCallback* callback) {
|
||
|
DCHECK(channel_id_key);
|
||
|
DCHECK(callback);
|
||
|
|
||
|
if (STATE_NONE != next_state_) {
|
||
|
DLOG(DFATAL) << "GetChannelIDKey has begun";
|
||
|
return quic::QUIC_FAILURE;
|
||
|
}
|
||
|
|
||
|
channel_id_key_.reset();
|
||
|
|
||
|
hostname_ = hostname;
|
||
|
|
||
|
next_state_ = STATE_GET_CHANNEL_ID_KEY;
|
||
|
switch (DoLoop(OK)) {
|
||
|
case OK:
|
||
|
*channel_id_key = std::move(channel_id_key_);
|
||
|
return quic::QUIC_SUCCESS;
|
||
|
case ERR_IO_PENDING:
|
||
|
callback_.reset(callback);
|
||
|
return quic::QUIC_PENDING;
|
||
|
default:
|
||
|
channel_id_key->reset();
|
||
|
return quic::QUIC_FAILURE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ChannelIDSourceChromium::Job::DoLoop(int last_result) {
|
||
|
int rv = last_result;
|
||
|
do {
|
||
|
State state = next_state_;
|
||
|
next_state_ = STATE_NONE;
|
||
|
switch (state) {
|
||
|
case STATE_GET_CHANNEL_ID_KEY:
|
||
|
DCHECK(rv == OK);
|
||
|
rv = DoGetChannelIDKey(rv);
|
||
|
break;
|
||
|
case STATE_GET_CHANNEL_ID_KEY_COMPLETE:
|
||
|
rv = DoGetChannelIDKeyComplete(rv);
|
||
|
break;
|
||
|
case STATE_NONE:
|
||
|
default:
|
||
|
rv = ERR_UNEXPECTED;
|
||
|
LOG(DFATAL) << "unexpected state " << state;
|
||
|
break;
|
||
|
}
|
||
|
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
void ChannelIDSourceChromium::Job::OnIOComplete(int result) {
|
||
|
int rv = DoLoop(result);
|
||
|
if (rv != ERR_IO_PENDING) {
|
||
|
std::unique_ptr<quic::ChannelIDSourceCallback> callback(
|
||
|
callback_.release());
|
||
|
callback->Run(&channel_id_key_);
|
||
|
// Will delete |this|.
|
||
|
channel_id_source_->OnJobComplete(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ChannelIDSourceChromium::Job::DoGetChannelIDKey(int result) {
|
||
|
next_state_ = STATE_GET_CHANNEL_ID_KEY_COMPLETE;
|
||
|
|
||
|
return channel_id_service_->GetOrCreateChannelID(
|
||
|
hostname_, &channel_id_crypto_key_,
|
||
|
base::Bind(&ChannelIDSourceChromium::Job::OnIOComplete,
|
||
|
base::Unretained(this)),
|
||
|
&channel_id_request_);
|
||
|
}
|
||
|
|
||
|
int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
|
||
|
DCHECK_EQ(STATE_NONE, next_state_);
|
||
|
if (result != OK) {
|
||
|
DLOG(WARNING) << "Failed to look up channel ID: " << ErrorToString(result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
DCHECK(channel_id_crypto_key_);
|
||
|
channel_id_key_.reset(
|
||
|
new ChannelIDKeyChromium(std::move(channel_id_crypto_key_)));
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
ChannelIDSourceChromium::ChannelIDSourceChromium(
|
||
|
ChannelIDService* channel_id_service)
|
||
|
: channel_id_service_(channel_id_service) {}
|
||
|
|
||
|
ChannelIDSourceChromium::~ChannelIDSourceChromium() {}
|
||
|
|
||
|
quic::QuicAsyncStatus ChannelIDSourceChromium::GetChannelIDKey(
|
||
|
const std::string& hostname,
|
||
|
std::unique_ptr<quic::ChannelIDKey>* channel_id_key,
|
||
|
quic::ChannelIDSourceCallback* callback) {
|
||
|
std::unique_ptr<Job> job = std::make_unique<Job>(this, channel_id_service_);
|
||
|
quic::QuicAsyncStatus status =
|
||
|
job->GetChannelIDKey(hostname, channel_id_key, callback);
|
||
|
if (status == quic::QUIC_PENDING) {
|
||
|
Job* job_ptr = job.get();
|
||
|
active_jobs_[job_ptr] = std::move(job);
|
||
|
}
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
void ChannelIDSourceChromium::OnJobComplete(Job* job) {
|
||
|
active_jobs_.erase(job);
|
||
|
}
|
||
|
|
||
|
} // namespace net
|