Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: chrome/browser/net/chrome_fraudulent_certificate_reporter.cc

Issue 975623002: Encrypt certificate logger requests for extended reporting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove stray comment Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/net/chrome_fraudulent_certificate_reporter.h" 5 #include "chrome/browser/net/chrome_fraudulent_certificate_reporter.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/profiler/scoped_tracker.h" 11 #include "base/profiler/scoped_tracker.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "base/time/time.h" 13 #include "base/time/time.h"
14 #include "chrome/browser/net/cert_logger.pb.h" 14 #include "chrome/browser/net/cert_logger.pb.h"
15 #include "crypto/curve25519.h"
16 #include "crypto/encryptor.h"
17 #include "crypto/hmac.h"
18 #include "crypto/random.h"
19 #include "crypto/sha2.h"
20 #include "crypto/symmetric_key.h"
15 #include "net/base/elements_upload_data_stream.h" 21 #include "net/base/elements_upload_data_stream.h"
16 #include "net/base/load_flags.h" 22 #include "net/base/load_flags.h"
17 #include "net/base/request_priority.h" 23 #include "net/base/request_priority.h"
18 #include "net/base/upload_bytes_element_reader.h" 24 #include "net/base/upload_bytes_element_reader.h"
19 #include "net/cert/x509_certificate.h" 25 #include "net/cert/x509_certificate.h"
20 #include "net/ssl/ssl_info.h" 26 #include "net/ssl/ssl_info.h"
21 #include "net/url_request/url_request_context.h" 27 #include "net/url_request/url_request_context.h"
22 28
23 namespace chrome_browser_net { 29 namespace chrome_browser_net {
24 30
25 // TODO(palmer): Switch to HTTPS when the error handling delegate is more 31 // TODO(palmer): Switch to HTTPS when the error handling delegate is more
26 // sophisticated. Ultimately we plan to attempt the report on many transports. 32 // sophisticated. Ultimately we plan to attempt the report on many transports.
27 static const char kFraudulentCertificateUploadEndpoint[] = 33 static const char kFraudulentCertificateUploadEndpoint[] =
28 "http://clients3.google.com/log_cert_error"; 34 "http://clients3.google.com/log_cert_error";
29 35
30 static const char kInvalidCertificateChainUploadEndpoint[] = ""; 36 static const char kInvalidCertificateChainUploadEndpoint[] = "";
31 37
38 // Constants used for crypto
39 static const uint8 kServerPublicKey[] = {
40 0xc5, 0x3e, 0x58, 0x9e, 0x43, 0xec, 0xbc, 0x84, 0xff, 0xec, 0x8d,
41 0x57, 0x20, 0xa3, 0x61, 0x60, 0xe1, 0x0b, 0x7d, 0x30, 0x5d, 0x3b,
42 0x2a, 0x90, 0xcf, 0x73, 0xe7, 0x61, 0xa8, 0x92, 0xa1, 0x79};
43 static const uint32 kServerPublicKeyVersion = 1;
44 static const uint32 kAesNonceSize = 16;
45
32 ChromeFraudulentCertificateReporter::ChromeFraudulentCertificateReporter( 46 ChromeFraudulentCertificateReporter::ChromeFraudulentCertificateReporter(
33 net::URLRequestContext* request_context) 47 net::URLRequestContext* request_context)
34 : request_context_(request_context), 48 : request_context_(request_context),
35 pinning_violation_upload_url_(kFraudulentCertificateUploadEndpoint), 49 pinning_violation_upload_url_(kFraudulentCertificateUploadEndpoint),
36 invalid_chain_upload_url_(kInvalidCertificateChainUploadEndpoint) { 50 invalid_chain_upload_url_(kInvalidCertificateChainUploadEndpoint) {
37 } 51 }
38 52
39 ChromeFraudulentCertificateReporter::~ChromeFraudulentCertificateReporter() { 53 ChromeFraudulentCertificateReporter::~ChromeFraudulentCertificateReporter() {
40 STLDeleteElements(&inflight_requests_); 54 STLDeleteElements(&inflight_requests_);
41 } 55 }
42 56
57 void CalculateSymmetricKeys(const uint8* client_private_key,
58 const uint8* server_public_key,
59 std::string& aes_key,
60 std::string& hmac_key) {
61 uint8 shared_secret[crypto::curve25519::kBytes];
62 uint8 symmetric_key[crypto::kSHA256Length];
63 crypto::curve25519::ScalarMult(client_private_key, server_public_key,
64 shared_secret);
65 crypto::SHA256HashString(
66 std::string((char*)shared_secret, sizeof(shared_secret)), symmetric_key,
67 sizeof(symmetric_key));
68
69 aes_key = std::string((char*)symmetric_key, sizeof(symmetric_key) / 2);
70 hmac_key = std::string((char*)(symmetric_key + sizeof(symmetric_key) / 2),
agl 2015/03/05 19:22:25 An HMAC-SHA256 key is generally 32 bytes. Also, if
71 sizeof(symmetric_key) / 2);
72 }
73
74 bool EncryptSerializedReport(const uint8* server_public_key,
75 uint32 server_public_key_version,
76 const std::string& report,
77 EncryptedCertLoggerRequest& encrypted_report) {
78 // Generate an ephemeral key pair to generate a shared secret.
79 uint8 public_key[crypto::curve25519::kBytes];
80 uint8 private_key[crypto::curve25519::kScalarBytes];
81 crypto::RandBytes(private_key, sizeof(private_key));
82 crypto::curve25519::ScalarBaseMult(private_key, public_key);
83
84 // Calculate the shared symmetric keys.
85 std::string aes_key_str;
86 std::string hmac_key;
87 CalculateSymmetricKeys(private_key, server_public_key, aes_key_str, hmac_key);
88 scoped_ptr<crypto::SymmetricKey> aes_key(
89 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, aes_key_str));
90
91 // Encrypt the serialized report with AES-CTR.
92 crypto::Encryptor encryptor;
93 char counter[kAesNonceSize];
agl 2015/03/05 19:22:25 s/char/uint8/
94 std::string ciphertext;
95 crypto::RandBytes(counter, kAesNonceSize);
agl 2015/03/05 19:22:25 as noted, the nonce can be all zeros because the k
96 encryptor.Init(aes_key.get(), crypto::Encryptor::CTR, "");
97 encryptor.SetCounter(std::string(counter, kAesNonceSize));
98 encryptor.Encrypt(report, &ciphertext);
99
100 // Compute HMAC-SHA256(nonce || ciphertext).
101 std::string hmac_input = std::string(counter, kAesNonceSize) + ciphertext;
102 crypto::HMAC hmac(crypto::HMAC::SHA256);
103 bool init_result = hmac.Init(hmac_key);
agl 2015/03/05 19:22:25 why does |init_result| and |hmac_result| exist? Yo
104 if (!init_result) {
105 LOG(ERROR) << "Failed to initialize HMAC.";
106 return init_result;
107 }
108
109 unsigned char digest[hmac.DigestLength()];
agl 2015/03/05 19:22:25 Aren't variable-length arrays a compiler extension
110 bool hmac_result = hmac.Sign(hmac_input, digest, sizeof(digest));
111 if (!hmac_result) {
112 LOG(ERROR) << "Failed to compute HMAC.";
113 return hmac_result;
114 }
115
116 encrypted_report.set_encrypted_report(ciphertext);
117 encrypted_report.set_server_public_key(server_public_key_version);
118 encrypted_report.set_client_public_key(
119 std::string((char*)public_key, crypto::curve25519::kBytes));
120 encrypted_report.set_nonce(std::string(counter, kAesNonceSize));
121 encrypted_report.set_mac(std::string((char*)digest, sizeof(digest)));
122 encrypted_report.set_algorithm(
123 EncryptedCertLoggerRequest::ECDH_AES_CTR_128_HMAC_SHA256);
124 return true;
125 }
126
43 static std::string BuildReport(const std::string& hostname, 127 static std::string BuildReport(const std::string& hostname,
44 const net::SSLInfo& ssl_info) { 128 const net::SSLInfo& ssl_info) {
45 CertLoggerRequest request; 129 CertLoggerRequest request;
46 base::Time now = base::Time::Now(); 130 base::Time now = base::Time::Now();
47 request.set_time_usec(now.ToInternalValue()); 131 request.set_time_usec(now.ToInternalValue());
48 request.set_hostname(hostname); 132 request.set_hostname(hostname);
49 133
50 std::vector<std::string> pem_encoded_chain; 134 std::vector<std::string> pem_encoded_chain;
51 if (!ssl_info.cert->GetPEMEncodedChain(&pem_encoded_chain)) { 135 if (!ssl_info.cert->GetPEMEncodedChain(&pem_encoded_chain)) {
52 LOG(ERROR) << "Could not get PEM encoded chain."; 136 LOG(ERROR) << "Could not get PEM encoded chain.";
(...skipping 17 matching lines...) Expand all
70 context->CreateRequest(upload_url, net::DEFAULT_PRIORITY, this, NULL); 154 context->CreateRequest(upload_url, net::DEFAULT_PRIORITY, this, NULL);
71 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 155 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
72 net::LOAD_DO_NOT_SAVE_COOKIES); 156 net::LOAD_DO_NOT_SAVE_COOKIES);
73 return request.Pass(); 157 return request.Pass();
74 } 158 }
75 159
76 void ChromeFraudulentCertificateReporter::SendReport( 160 void ChromeFraudulentCertificateReporter::SendReport(
77 ReportType type, 161 ReportType type,
78 const std::string& hostname, 162 const std::string& hostname,
79 const net::SSLInfo& ssl_info) { 163 const net::SSLInfo& ssl_info) {
164 // We do silent/automatic reporting ONLY for Google properties. For other
165 // domains (when we start supporting that), we will ask for user permission.
166 if (type == REPORT_TYPE_PIN_VIOLATION &&
167 !net::TransportSecurityState::IsGooglePinnedProperty(hostname)) {
168 return;
169 }
170
171 std::string report = BuildReport(hostname, ssl_info);
172
80 if (type == REPORT_TYPE_EXTENDED_REPORTING) { 173 if (type == REPORT_TYPE_EXTENDED_REPORTING) {
81 // TODO(estark): Double-check that the user is opted in. 174 // TODO(estark): Double-check that the user is opted in.
82 175
83 // TODO(estark): Temporarily, since there is no upload endpoint, just log 176 // TODO(estark): Temporarily, since there is no upload endpoint, just log
84 // the information. 177 // the information.
85 LOG(ERROR) << "SSL report for " << hostname << ":\n" 178 LOG(ERROR) << "SSL report for " << hostname << ":\n" << report << "\n\n";
86 << BuildReport(hostname, ssl_info) << "\n\n"; 179
180 EncryptedCertLoggerRequest encrypted_request;
181 bool result = EncryptSerializedReport(
182 kServerPublicKey, kServerPublicKeyVersion, report, encrypted_request);
183 if (!result) {
184 LOG(ERROR) << "Failed to encrypt serialized report.";
185 return;
186 }
187
188 std::string encrypted_report;
189 encrypted_request.SerializeToString(&encrypted_report);
190 LOG(ERROR) << "Encrypted: " << encrypted_report;
191
87 return; 192 return;
88 } 193 }
89 194
90 // We do silent/automatic reporting ONLY for Google properties. For other
91 // domains (when we start supporting that), we will ask for user permission.
92 if (!net::TransportSecurityState::IsGooglePinnedProperty(hostname)) {
93 return;
94 }
95
96 std::string report = BuildReport(hostname, ssl_info);
97
98 scoped_ptr<net::URLRequest> url_request = 195 scoped_ptr<net::URLRequest> url_request =
99 CreateURLRequest(request_context_, pinning_violation_upload_url_); 196 CreateURLRequest(request_context_, pinning_violation_upload_url_);
100 url_request->set_method("POST"); 197 url_request->set_method("POST");
101 198
102 scoped_ptr<net::UploadElementReader> reader( 199 scoped_ptr<net::UploadElementReader> reader(
103 net::UploadOwnedBytesElementReader::CreateWithString(report)); 200 net::UploadOwnedBytesElementReader::CreateWithString(report));
104 url_request->set_upload( 201 url_request->set_upload(
105 net::ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0)); 202 net::ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
106 203
107 net::HttpRequestHeaders headers; 204 net::HttpRequestHeaders headers;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 LOG(WARNING) << "Certificate upload HTTP status: " 238 LOG(WARNING) << "Certificate upload HTTP status: "
142 << request->GetResponseCode(); 239 << request->GetResponseCode();
143 } 240 }
144 RequestComplete(request); 241 RequestComplete(request);
145 } 242 }
146 243
147 void ChromeFraudulentCertificateReporter::OnReadCompleted( 244 void ChromeFraudulentCertificateReporter::OnReadCompleted(
148 net::URLRequest* request, int bytes_read) {} 245 net::URLRequest* request, int bytes_read) {}
149 246
150 } // namespace chrome_browser_net 247 } // namespace chrome_browser_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698