Chromium Code Reviews| 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 15dad135b373587ed318c3ac384c801275367e4b..bcf11680de7aa5b1f5532abbf563cc4a88b78a61 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) |
|
estark
2015/04/18 05:24:42
Should I be checking OPENSSL_IS_BORINGSSL too? It
agl
2015/04/21 20:28:25
No, OpenSSL in Chrome is always BoringSSL.
estark
2015/04/22 03:55:30
Acknowledged.
|
| +#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,117 @@ |
| #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) |
| +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::HKDF hkdf(std::string((char*)shared_secret, sizeof(shared_secret)), |
| + std::string(), std::string(), 0, 0, |
|
agl
2015/04/21 20:28:25
I'd suggest adding an info argument (the 3rd) of s
estark
2015/04/22 03:55:30
Done.
|
| + crypto::Aead::KeyLength()); |
| + |
| + const std::string key(hkdf.subkey_secret().data(), |
| + hkdf.subkey_secret().size()); |
| + crypto::Aead aead(&key); |
| + |
| + // Use an all-zero nonce because the key is random per-message. |
| + std::string nonce(crypto::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, crypto::curve25519::kBytes)); |
|
agl
2015/04/21 20:28:25
sizeof(public_key)
estark
2015/04/22 03:55:30
Done.
|
| + encrypted_report->set_algorithm( |
| + chrome_browser_net::EncryptedCertLoggerRequest:: |
| + AEAD_ECDH_AES_128_CTR_HMAC_SHA256); |
| + return true; |
| +} |
| +#endif |
| + |
| +} // namespace |
| + |
| namespace chrome_browser_net { |
| +// Used only by tests. |
| +#if defined(USE_OPENSSL) |
| +bool 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::HKDF hkdf(std::string((char*)shared_secret, sizeof(shared_secret)), |
| + std::string(), std::string(), 0, 0, |
|
agl
2015/04/21 20:28:25
the info would also have to be updated here.
estark
2015/04/22 03:55:30
Done.
|
| + crypto::Aead::KeyLength()); |
| + |
| + const std::string key(hkdf.subkey_secret().data(), |
| + hkdf.subkey_secret().size()); |
| + crypto::Aead aead(&key); |
| + |
| + // Use an all-zero nonce because the key is random per-message. |
| + std::string nonce(crypto::Aead::NonceLength(), 0); |
| + |
| + std::string plaintext; |
| + if (!aead.Open(encrypted_report.encrypted_report(), nonce, &plaintext)) { |
| + LOG(ERROR) << "Error opening certificate report"; |
| + return false; |
| + } |
| + |
| + decrypted_report->ParseFromString(plaintext); |
|
agl
2015/04/21 20:28:25
this can fail, right? Just return it directly?
estark
2015/04/22 03:55:30
Done.
|
| + return true; |
| +} |
| +#endif |
| + |
| 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 +148,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 +155,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_.SchemeIsSecure()); |
| - SendCertLoggerRequest(request); |
| + if (upload_url_.SchemeIsSecure()) { |
| + 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 +208,23 @@ scoped_ptr<net::URLRequest> CertificateErrorReporter::CreateURLRequest( |
| return request.Pass(); |
| } |
| +bool CertificateErrorReporter::IsHttpUploadUrlSupported() { |
| +#if defined(USE_OPENSSL) |
| + return true; |
| +#else |
| + return false; |
| +#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"); |