Index: chrome/browser/net/certificate_error_reporter.cc |
diff --git a/chrome/browser/net/certificate_error_reporter.cc b/chrome/browser/net/certificate_error_reporter.cc |
index 279209c6ba2499c781eec14d720e7b02d9f5e3a2..edff489f4ca0762dac6eb03bf554a1bc7e0adef2 100644 |
--- a/chrome/browser/net/certificate_error_reporter.cc |
+++ b/chrome/browser/net/certificate_error_reporter.cc |
@@ -10,6 +10,14 @@ |
#include "base/stl_util.h" |
#include "base/time/time.h" |
#include "chrome/browser/net/cert_logger.pb.h" |
+ |
+#if defined(USE_OPENSSL) |
+#include "crypto/aead_openssl.h" |
+#endif |
+ |
+#include "crypto/curve25519.h" |
+#include "crypto/hkdf.h" |
+#include "crypto/random.h" |
#include "net/base/elements_upload_data_stream.h" |
#include "net/base/load_flags.h" |
#include "net/base/request_priority.h" |
@@ -18,15 +26,87 @@ |
#include "net/ssl/ssl_info.h" |
#include "net/url_request/url_request_context.h" |
+namespace { |
+ |
+// Constants used for crypto |
+static const uint8 kServerPublicKey[] = { |
+ 0x51, 0xcc, 0x52, 0x67, 0x42, 0x47, 0x3b, 0x10, 0xe8, 0x63, 0x18, |
+ 0x3c, 0x61, 0xa7, 0x96, 0x76, 0x86, 0x91, 0x40, 0x71, 0x39, 0x5f, |
+ 0x31, 0x1a, 0x39, 0x5b, 0x76, 0xb1, 0x6b, 0x3d, 0x6a, 0x2b}; |
+static const uint32 kServerPublicKeyVersion = 1; |
+ |
+#if defined(USE_OPENSSL) |
+ |
+static const char kHkdfLabel[] = "certificate report"; |
+ |
+bool EncryptSerializedReport( |
+ const uint8* server_public_key, |
+ uint32 server_public_key_version, |
+ const std::string& report, |
+ chrome_browser_net::EncryptedCertLoggerRequest* encrypted_report) { |
+ // Generate an ephemeral key pair to generate a shared secret. |
+ uint8 public_key[crypto::curve25519::kBytes]; |
+ uint8 private_key[crypto::curve25519::kScalarBytes]; |
+ uint8 shared_secret[crypto::curve25519::kBytes]; |
+ |
+ crypto::RandBytes(private_key, sizeof(private_key)); |
+ crypto::curve25519::ScalarBaseMult(private_key, public_key); |
+ crypto::curve25519::ScalarMult(private_key, server_public_key, shared_secret); |
+ |
+ crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); |
+ crypto::HKDF hkdf(std::string((char*)shared_secret, sizeof(shared_secret)), |
+ kHkdfLabel, std::string(), 0, 0, aead.KeyLength()); |
+ |
+ const std::string key(hkdf.subkey_secret().data(), |
+ hkdf.subkey_secret().size()); |
+ aead.Init(&key); |
+ |
+ // Use an all-zero nonce because the key is random per-message. |
+ std::string nonce(aead.NonceLength(), 0); |
+ |
+ std::string ciphertext; |
+ if (!aead.Seal(report, nonce, "", &ciphertext)) { |
+ LOG(ERROR) << "Error sealing certificate report."; |
+ return false; |
+ } |
+ |
+ encrypted_report->set_encrypted_report(ciphertext); |
+ encrypted_report->set_server_public_key_version(server_public_key_version); |
+ encrypted_report->set_client_public_key( |
+ std::string((char*)public_key, sizeof(public_key))); |
+ encrypted_report->set_algorithm( |
+ chrome_browser_net::EncryptedCertLoggerRequest:: |
+ AEAD_ECDH_AES_128_CTR_HMAC_SHA256); |
+ return true; |
+} |
+#endif |
+ |
+} // namespace |
+ |
namespace chrome_browser_net { |
CertificateErrorReporter::CertificateErrorReporter( |
net::URLRequestContext* request_context, |
const GURL& upload_url, |
CookiesPreference cookies_preference) |
+ : CertificateErrorReporter(request_context, |
+ upload_url, |
+ cookies_preference, |
+ kServerPublicKey, |
+ kServerPublicKeyVersion) { |
+} |
+ |
+CertificateErrorReporter::CertificateErrorReporter( |
+ net::URLRequestContext* request_context, |
+ const GURL& upload_url, |
+ CookiesPreference cookies_preference, |
+ const uint8 server_public_key[32], |
+ const uint32 server_public_key_version) |
: request_context_(request_context), |
upload_url_(upload_url), |
- cookies_preference_(cookies_preference) { |
+ cookies_preference_(cookies_preference), |
+ server_public_key_(server_public_key), |
+ server_public_key_version_(server_public_key_version) { |
DCHECK(!upload_url.is_empty()); |
} |
@@ -38,8 +118,6 @@ void CertificateErrorReporter::SendReport(ReportType type, |
const std::string& hostname, |
const net::SSLInfo& ssl_info) { |
CertLoggerRequest request; |
- std::string out; |
- |
BuildReport(hostname, ssl_info, &request); |
switch (type) { |
@@ -47,9 +125,25 @@ void CertificateErrorReporter::SendReport(ReportType type, |
SendCertLoggerRequest(request); |
break; |
case REPORT_TYPE_EXTENDED_REPORTING: |
- // TODO(estark): Encrypt the report if not sending over HTTPS. |
- DCHECK(upload_url_.SchemeIsCryptographic()); |
- SendCertLoggerRequest(request); |
+ if (upload_url_.SchemeIsCryptographic()) { |
+ SendCertLoggerRequest(request); |
+ } else { |
+ DCHECK(IsHttpUploadUrlSupported()); |
+#if defined(USE_OPENSSL) |
+ EncryptedCertLoggerRequest encrypted_report; |
+ std::string serialized_report; |
+ request.SerializeToString(&serialized_report); |
+ if (!EncryptSerializedReport(server_public_key_, |
+ server_public_key_version_, |
+ serialized_report, &encrypted_report)) { |
+ LOG(ERROR) << "Failed to encrypt serialized report."; |
+ return; |
+ } |
+ std::string serialized_encrypted_report; |
+ encrypted_report.SerializeToString(&serialized_encrypted_report); |
+ SendSerializedRequest(serialized_encrypted_report); |
+#endif |
+ } |
break; |
default: |
NOTREACHED(); |
@@ -84,11 +178,55 @@ scoped_ptr<net::URLRequest> CertificateErrorReporter::CreateURLRequest( |
return request.Pass(); |
} |
+bool CertificateErrorReporter::IsHttpUploadUrlSupported() { |
+#if defined(USE_OPENSSL) |
+ return true; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+// Used only by tests. |
+#if defined(USE_OPENSSL) |
+bool CertificateErrorReporter::DecryptCertificateErrorReport( |
+ const uint8 server_private_key[32], |
+ const EncryptedCertLoggerRequest& encrypted_report, |
+ CertLoggerRequest* decrypted_report) { |
+ uint8 shared_secret[crypto::curve25519::kBytes]; |
+ crypto::curve25519::ScalarMult( |
+ server_private_key, (uint8*)encrypted_report.client_public_key().data(), |
+ shared_secret); |
+ |
+ crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); |
+ crypto::HKDF hkdf(std::string((char*)shared_secret, sizeof(shared_secret)), |
+ kHkdfLabel, std::string(), 0, 0, aead.KeyLength()); |
+ |
+ const std::string key(hkdf.subkey_secret().data(), |
+ hkdf.subkey_secret().size()); |
+ aead.Init(&key); |
+ |
+ // Use an all-zero nonce because the key is random per-message. |
+ std::string nonce(aead.NonceLength(), 0); |
+ |
+ std::string plaintext; |
+ if (!aead.Open(encrypted_report.encrypted_report(), nonce, "", &plaintext)) { |
+ LOG(ERROR) << "Error opening certificate report"; |
+ return false; |
+ } |
+ |
+ return decrypted_report->ParseFromString(plaintext); |
+} |
+#endif |
+ |
void CertificateErrorReporter::SendCertLoggerRequest( |
const CertLoggerRequest& request) { |
std::string serialized_request; |
request.SerializeToString(&serialized_request); |
+ SendSerializedRequest(serialized_request); |
+} |
+void CertificateErrorReporter::SendSerializedRequest( |
+ const std::string& serialized_request) { |
scoped_ptr<net::URLRequest> url_request = CreateURLRequest(request_context_); |
url_request->set_method("POST"); |