[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / net / quic / crypto / channel_id_chromium.cc
blobab50efa8e1f79ff9f897e2842fac3e319b89fabe
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
3 // found in the LICENSE file.
5 #include "net/quic/crypto/channel_id_chromium.h"
7 #include <string>
9 #include "base/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "crypto/ec_private_key.h"
12 #include "crypto/ec_signature_creator.h"
13 #include "net/base/net_errors.h"
14 #include "net/cert/asn1_util.h"
15 #include "net/ssl/channel_id_service.h"
17 namespace net {
19 ChannelIDKeyChromium::ChannelIDKeyChromium(
20 scoped_ptr<crypto::ECPrivateKey> ec_private_key)
21 : ec_private_key_(ec_private_key.Pass()) {
24 ChannelIDKeyChromium::~ChannelIDKeyChromium() {}
26 bool ChannelIDKeyChromium::Sign(base::StringPiece signed_data,
27 std::string* out_signature) const {
28 scoped_ptr<crypto::ECSignatureCreator> sig_creator(
29 crypto::ECSignatureCreator::Create(ec_private_key_.get()));
30 if (!sig_creator) {
31 return false;
33 const size_t len1 = strlen(ChannelIDVerifier::kContextStr) + 1;
34 const size_t len2 = strlen(ChannelIDVerifier::kClientToServerStr) + 1;
35 std::vector<uint8> data(len1 + len2 + signed_data.size());
36 memcpy(&data[0], ChannelIDVerifier::kContextStr, len1);
37 memcpy(&data[len1], ChannelIDVerifier::kClientToServerStr, len2);
38 memcpy(&data[len1 + len2], signed_data.data(), signed_data.size());
39 std::vector<uint8> der_signature;
40 if (!sig_creator->Sign(&data[0], data.size(), &der_signature)) {
41 return false;
43 std::vector<uint8> raw_signature;
44 if (!sig_creator->DecodeSignature(der_signature, &raw_signature)) {
45 return false;
47 memcpy(WriteInto(out_signature, raw_signature.size() + 1),
48 &raw_signature[0], raw_signature.size());
49 return true;
52 std::string ChannelIDKeyChromium::SerializeKey() const {
53 std::string out_key;
54 if (!ec_private_key_->ExportRawPublicKey(&out_key)) {
55 return std::string();
57 return out_key;
60 // A Job handles the lookup of a single channel ID. It is owned by the
61 // ChannelIDSource. If the operation can not complete synchronously, it will
62 // notify the ChannelIDSource upon completion.
63 class ChannelIDSourceChromium::Job {
64 public:
65 Job(ChannelIDSourceChromium* channel_id_source,
66 ChannelIDService* channel_id_service);
68 // Starts the channel ID lookup. If |QUIC_PENDING| is returned, then
69 // |callback| will be invoked asynchronously when the operation completes.
70 QuicAsyncStatus GetChannelIDKey(const std::string& hostname,
71 scoped_ptr<ChannelIDKey>* channel_id_key,
72 ChannelIDSourceCallback* callback);
74 private:
75 enum State {
76 STATE_NONE,
77 STATE_GET_CHANNEL_ID_KEY,
78 STATE_GET_CHANNEL_ID_KEY_COMPLETE,
81 int DoLoop(int last_io_result);
82 void OnIOComplete(int result);
83 int DoGetChannelIDKey(int result);
84 int DoGetChannelIDKeyComplete(int result);
86 // Channel ID source to notify when this jobs completes.
87 ChannelIDSourceChromium* const channel_id_source_;
89 ChannelIDService* const channel_id_service_;
91 scoped_ptr<crypto::ECPrivateKey> channel_id_crypto_key_;
92 ChannelIDService::Request channel_id_request_;
94 // |hostname| specifies the hostname for which we need a channel ID.
95 std::string hostname_;
97 scoped_ptr<ChannelIDSourceCallback> callback_;
99 scoped_ptr<ChannelIDKey> channel_id_key_;
101 State next_state_;
103 DISALLOW_COPY_AND_ASSIGN(Job);
106 ChannelIDSourceChromium::Job::Job(
107 ChannelIDSourceChromium* channel_id_source,
108 ChannelIDService* channel_id_service)
109 : channel_id_source_(channel_id_source),
110 channel_id_service_(channel_id_service),
111 next_state_(STATE_NONE) {
114 QuicAsyncStatus ChannelIDSourceChromium::Job::GetChannelIDKey(
115 const std::string& hostname,
116 scoped_ptr<ChannelIDKey>* channel_id_key,
117 ChannelIDSourceCallback* callback) {
118 DCHECK(channel_id_key);
119 DCHECK(callback);
121 if (STATE_NONE != next_state_) {
122 DLOG(DFATAL) << "GetChannelIDKey has begun";
123 return QUIC_FAILURE;
126 channel_id_key_.reset();
128 hostname_ = hostname;
130 next_state_ = STATE_GET_CHANNEL_ID_KEY;
131 switch (DoLoop(OK)) {
132 case OK:
133 channel_id_key->reset(channel_id_key_.release());
134 return QUIC_SUCCESS;
135 case ERR_IO_PENDING:
136 callback_.reset(callback);
137 return QUIC_PENDING;
138 default:
139 channel_id_key->reset();
140 return QUIC_FAILURE;
144 int ChannelIDSourceChromium::Job::DoLoop(int last_result) {
145 int rv = last_result;
146 do {
147 State state = next_state_;
148 next_state_ = STATE_NONE;
149 switch (state) {
150 case STATE_GET_CHANNEL_ID_KEY:
151 DCHECK(rv == OK);
152 rv = DoGetChannelIDKey(rv);
153 break;
154 case STATE_GET_CHANNEL_ID_KEY_COMPLETE:
155 rv = DoGetChannelIDKeyComplete(rv);
156 break;
157 case STATE_NONE:
158 default:
159 rv = ERR_UNEXPECTED;
160 LOG(DFATAL) << "unexpected state " << state;
161 break;
163 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
164 return rv;
167 void ChannelIDSourceChromium::Job::OnIOComplete(int result) {
168 int rv = DoLoop(result);
169 if (rv != ERR_IO_PENDING) {
170 scoped_ptr<ChannelIDSourceCallback> callback(callback_.release());
171 callback->Run(&channel_id_key_);
172 // Will delete |this|.
173 channel_id_source_->OnJobComplete(this);
177 int ChannelIDSourceChromium::Job::DoGetChannelIDKey(int result) {
178 next_state_ = STATE_GET_CHANNEL_ID_KEY_COMPLETE;
180 return channel_id_service_->GetOrCreateChannelID(
181 hostname_, &channel_id_crypto_key_,
182 base::Bind(&ChannelIDSourceChromium::Job::OnIOComplete,
183 base::Unretained(this)),
184 &channel_id_request_);
187 int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
188 DCHECK_EQ(STATE_NONE, next_state_);
189 if (result != OK) {
190 DLOG(WARNING) << "Failed to look up channel ID: " << ErrorToString(result);
191 return result;
194 if (!channel_id_crypto_key_) {
195 // TODO(wtc): use the new error code ERR_CHANNEL_ID_IMPORT_FAILED to be
196 // added in https://codereview.chromium.org/338093012/.
197 return ERR_UNEXPECTED;
199 channel_id_key_.reset(
200 new ChannelIDKeyChromium(channel_id_crypto_key_.Pass()));
202 return result;
205 ChannelIDSourceChromium::ChannelIDSourceChromium(
206 ChannelIDService* channel_id_service)
207 : channel_id_service_(channel_id_service) {
210 ChannelIDSourceChromium::~ChannelIDSourceChromium() {
211 STLDeleteElements(&active_jobs_);
214 QuicAsyncStatus ChannelIDSourceChromium::GetChannelIDKey(
215 const std::string& hostname,
216 scoped_ptr<ChannelIDKey>* channel_id_key,
217 ChannelIDSourceCallback* callback) {
218 scoped_ptr<Job> job(new Job(this, channel_id_service_));
219 QuicAsyncStatus status = job->GetChannelIDKey(hostname, channel_id_key,
220 callback);
221 if (status == QUIC_PENDING) {
222 active_jobs_.insert(job.release());
224 return status;
227 void ChannelIDSourceChromium::OnJobComplete(Job* job) {
228 active_jobs_.erase(job);
229 delete job;
232 } // namespace net