Remove finch gate for uploading certificate reports over HTTP
[chromium-blink-merge.git] / chrome / browser / net / certificate_error_reporter.cc
blobc1f15914001244b9ebfb3fb563ea800e3d11f863
1 // Copyright 2015 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 "chrome/browser/net/certificate_error_reporter.h"
7 #include <set>
9 #include "base/logging.h"
10 #include "chrome/browser/net/encrypted_cert_logger.pb.h"
12 #if defined(USE_OPENSSL)
13 #include "crypto/aead_openssl.h"
14 #endif
16 #include "crypto/curve25519.h"
17 #include "crypto/hkdf.h"
18 #include "crypto/random.h"
19 #include "net/base/elements_upload_data_stream.h"
20 #include "net/base/load_flags.h"
21 #include "net/base/request_priority.h"
22 #include "net/base/upload_bytes_element_reader.h"
23 #include "net/url_request/url_request_context.h"
25 namespace {
27 // Constants used for crypto
28 static const uint8 kServerPublicKey[] = {
29 0x51, 0xcc, 0x52, 0x67, 0x42, 0x47, 0x3b, 0x10, 0xe8, 0x63, 0x18,
30 0x3c, 0x61, 0xa7, 0x96, 0x76, 0x86, 0x91, 0x40, 0x71, 0x39, 0x5f,
31 0x31, 0x1a, 0x39, 0x5b, 0x76, 0xb1, 0x6b, 0x3d, 0x6a, 0x2b};
32 static const uint32 kServerPublicKeyVersion = 1;
34 #if defined(USE_OPENSSL)
36 static const char kHkdfLabel[] = "certificate report";
38 bool EncryptSerializedReport(
39 const uint8* server_public_key,
40 uint32 server_public_key_version,
41 const std::string& report,
42 chrome_browser_net::EncryptedCertLoggerRequest* encrypted_report) {
43 // Generate an ephemeral key pair to generate a shared secret.
44 uint8 public_key[crypto::curve25519::kBytes];
45 uint8 private_key[crypto::curve25519::kScalarBytes];
46 uint8 shared_secret[crypto::curve25519::kBytes];
48 crypto::RandBytes(private_key, sizeof(private_key));
49 crypto::curve25519::ScalarBaseMult(private_key, public_key);
50 crypto::curve25519::ScalarMult(private_key, server_public_key, shared_secret);
52 crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256);
53 crypto::HKDF hkdf(std::string(reinterpret_cast<char*>(shared_secret),
54 sizeof(shared_secret)),
55 std::string(),
56 base::StringPiece(kHkdfLabel, sizeof(kHkdfLabel)), 0, 0,
57 aead.KeyLength());
59 const std::string key(hkdf.subkey_secret().data(),
60 hkdf.subkey_secret().size());
61 aead.Init(&key);
63 // Use an all-zero nonce because the key is random per-message.
64 std::string nonce(aead.NonceLength(), 0);
66 std::string ciphertext;
67 if (!aead.Seal(report, nonce, std::string(), &ciphertext)) {
68 LOG(ERROR) << "Error sealing certificate report.";
69 return false;
72 encrypted_report->set_encrypted_report(ciphertext);
73 encrypted_report->set_server_public_key_version(server_public_key_version);
74 encrypted_report->set_client_public_key(
75 std::string(reinterpret_cast<char*>(public_key), sizeof(public_key)));
76 encrypted_report->set_algorithm(
77 chrome_browser_net::EncryptedCertLoggerRequest::
78 AEAD_ECDH_AES_128_CTR_HMAC_SHA256);
79 return true;
81 #endif
83 } // namespace
85 namespace chrome_browser_net {
87 CertificateErrorReporter::CertificateErrorReporter(
88 net::URLRequestContext* request_context,
89 const GURL& upload_url,
90 CookiesPreference cookies_preference)
91 : CertificateErrorReporter(request_context,
92 upload_url,
93 cookies_preference,
94 kServerPublicKey,
95 kServerPublicKeyVersion) {
98 CertificateErrorReporter::CertificateErrorReporter(
99 net::URLRequestContext* request_context,
100 const GURL& upload_url,
101 CookiesPreference cookies_preference,
102 const uint8 server_public_key[32],
103 const uint32 server_public_key_version)
104 : request_context_(request_context),
105 upload_url_(upload_url),
106 cookies_preference_(cookies_preference),
107 server_public_key_(server_public_key),
108 server_public_key_version_(server_public_key_version) {
109 DCHECK(!upload_url.is_empty());
112 CertificateErrorReporter::~CertificateErrorReporter() {
113 STLDeleteElements(&inflight_requests_);
116 void CertificateErrorReporter::SendReport(
117 ReportType type,
118 const std::string& serialized_report) {
119 switch (type) {
120 case REPORT_TYPE_PINNING_VIOLATION:
121 SendSerializedRequest(serialized_report);
122 break;
123 case REPORT_TYPE_EXTENDED_REPORTING:
124 if (upload_url_.SchemeIsCryptographic()) {
125 SendSerializedRequest(serialized_report);
126 } else {
127 DCHECK(IsHttpUploadUrlSupported());
128 #if defined(USE_OPENSSL)
129 EncryptedCertLoggerRequest encrypted_report;
130 if (!EncryptSerializedReport(server_public_key_,
131 server_public_key_version_,
132 serialized_report, &encrypted_report)) {
133 LOG(ERROR) << "Failed to encrypt serialized report.";
134 return;
136 std::string serialized_encrypted_report;
137 encrypted_report.SerializeToString(&serialized_encrypted_report);
138 SendSerializedRequest(serialized_encrypted_report);
139 #endif
141 break;
142 default:
143 NOTREACHED();
147 void CertificateErrorReporter::OnResponseStarted(net::URLRequest* request) {
148 const net::URLRequestStatus& status(request->status());
149 if (!status.is_success()) {
150 LOG(WARNING) << "Certificate upload failed"
151 << " status:" << status.status()
152 << " error:" << status.error();
153 } else if (request->GetResponseCode() != 200) {
154 LOG(WARNING) << "Certificate upload HTTP status: "
155 << request->GetResponseCode();
157 RequestComplete(request);
160 void CertificateErrorReporter::OnReadCompleted(net::URLRequest* request,
161 int bytes_read) {
164 scoped_ptr<net::URLRequest> CertificateErrorReporter::CreateURLRequest(
165 net::URLRequestContext* context) {
166 scoped_ptr<net::URLRequest> request =
167 context->CreateRequest(upload_url_, net::DEFAULT_PRIORITY, this);
168 if (cookies_preference_ != SEND_COOKIES) {
169 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
170 net::LOAD_DO_NOT_SAVE_COOKIES);
172 return request.Pass();
175 bool CertificateErrorReporter::IsHttpUploadUrlSupported() {
176 #if defined(USE_OPENSSL)
177 return true;
178 #else
179 return false;
180 #endif
183 // Used only by tests.
184 #if defined(USE_OPENSSL)
185 bool CertificateErrorReporter::DecryptCertificateErrorReport(
186 const uint8 server_private_key[32],
187 const EncryptedCertLoggerRequest& encrypted_report,
188 std::string* decrypted_serialized_report) {
189 uint8 shared_secret[crypto::curve25519::kBytes];
190 crypto::curve25519::ScalarMult(
191 server_private_key, reinterpret_cast<const uint8*>(
192 encrypted_report.client_public_key().data()),
193 shared_secret);
195 crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256);
196 crypto::HKDF hkdf(std::string(reinterpret_cast<char*>(shared_secret),
197 sizeof(shared_secret)),
198 std::string(),
199 base::StringPiece(kHkdfLabel, sizeof(kHkdfLabel)), 0, 0,
200 aead.KeyLength());
202 const std::string key(hkdf.subkey_secret().data(),
203 hkdf.subkey_secret().size());
204 aead.Init(&key);
206 // Use an all-zero nonce because the key is random per-message.
207 std::string nonce(aead.NonceLength(), 0);
209 return aead.Open(encrypted_report.encrypted_report(), nonce, std::string(),
210 decrypted_serialized_report);
212 #endif
214 void CertificateErrorReporter::SendSerializedRequest(
215 const std::string& serialized_request) {
216 scoped_ptr<net::URLRequest> url_request = CreateURLRequest(request_context_);
217 url_request->set_method("POST");
219 scoped_ptr<net::UploadElementReader> reader(
220 net::UploadOwnedBytesElementReader::CreateWithString(serialized_request));
221 url_request->set_upload(
222 net::ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
224 net::HttpRequestHeaders headers;
225 headers.SetHeader(net::HttpRequestHeaders::kContentType,
226 "x-application/chrome-fraudulent-cert-report");
227 url_request->SetExtraRequestHeaders(headers);
229 net::URLRequest* raw_url_request = url_request.get();
230 inflight_requests_.insert(url_request.release());
231 raw_url_request->Start();
234 void CertificateErrorReporter::RequestComplete(net::URLRequest* request) {
235 std::set<net::URLRequest*>::iterator i = inflight_requests_.find(request);
236 DCHECK(i != inflight_requests_.end());
237 scoped_ptr<net::URLRequest> url_request(*i);
238 inflight_requests_.erase(i);
241 } // namespace chrome_browser_net