Index: chrome/browser/net/chrome_fraudulent_certificate_reporter.cc |
diff --git a/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc b/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc |
index 0e3a1d658533a4678f51c441ac05704cf2651547..e3f43613170f3157b583743f15270b634e2d2ed7 100644 |
--- a/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc |
+++ b/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc |
@@ -12,6 +12,12 @@ |
#include "base/stl_util.h" |
#include "base/time/time.h" |
#include "chrome/browser/net/cert_logger.pb.h" |
+#include "crypto/curve25519.h" |
+#include "crypto/encryptor.h" |
+#include "crypto/hmac.h" |
+#include "crypto/random.h" |
+#include "crypto/sha2.h" |
+#include "crypto/symmetric_key.h" |
#include "net/base/elements_upload_data_stream.h" |
#include "net/base/load_flags.h" |
#include "net/base/request_priority.h" |
@@ -29,6 +35,14 @@ static const char kFraudulentCertificateUploadEndpoint[] = |
static const char kInvalidCertificateChainUploadEndpoint[] = ""; |
+// Constants used for crypto |
+static const uint8 kServerPublicKey[] = { |
+ 0xc5, 0x3e, 0x58, 0x9e, 0x43, 0xec, 0xbc, 0x84, 0xff, 0xec, 0x8d, |
+ 0x57, 0x20, 0xa3, 0x61, 0x60, 0xe1, 0x0b, 0x7d, 0x30, 0x5d, 0x3b, |
+ 0x2a, 0x90, 0xcf, 0x73, 0xe7, 0x61, 0xa8, 0x92, 0xa1, 0x79}; |
+static const uint32 kServerPublicKeyVersion = 1; |
+static const uint32 kAesNonceSize = 16; |
+ |
ChromeFraudulentCertificateReporter::ChromeFraudulentCertificateReporter( |
net::URLRequestContext* request_context) |
: request_context_(request_context), |
@@ -40,6 +54,76 @@ ChromeFraudulentCertificateReporter::~ChromeFraudulentCertificateReporter() { |
STLDeleteElements(&inflight_requests_); |
} |
+void CalculateSymmetricKeys(const uint8* client_private_key, |
+ const uint8* server_public_key, |
+ std::string& aes_key, |
+ std::string& hmac_key) { |
+ uint8 shared_secret[crypto::curve25519::kBytes]; |
+ uint8 symmetric_key[crypto::kSHA256Length]; |
+ crypto::curve25519::ScalarMult(client_private_key, server_public_key, |
+ shared_secret); |
+ crypto::SHA256HashString( |
+ std::string((char*)shared_secret, sizeof(shared_secret)), symmetric_key, |
+ sizeof(symmetric_key)); |
+ |
+ aes_key = std::string((char*)symmetric_key, sizeof(symmetric_key) / 2); |
+ 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
|
+ sizeof(symmetric_key) / 2); |
+} |
+ |
+bool EncryptSerializedReport(const uint8* server_public_key, |
+ uint32 server_public_key_version, |
+ const std::string& report, |
+ 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]; |
+ crypto::RandBytes(private_key, sizeof(private_key)); |
+ crypto::curve25519::ScalarBaseMult(private_key, public_key); |
+ |
+ // Calculate the shared symmetric keys. |
+ std::string aes_key_str; |
+ std::string hmac_key; |
+ CalculateSymmetricKeys(private_key, server_public_key, aes_key_str, hmac_key); |
+ scoped_ptr<crypto::SymmetricKey> aes_key( |
+ crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, aes_key_str)); |
+ |
+ // Encrypt the serialized report with AES-CTR. |
+ crypto::Encryptor encryptor; |
+ char counter[kAesNonceSize]; |
agl
2015/03/05 19:22:25
s/char/uint8/
|
+ std::string ciphertext; |
+ crypto::RandBytes(counter, kAesNonceSize); |
agl
2015/03/05 19:22:25
as noted, the nonce can be all zeros because the k
|
+ encryptor.Init(aes_key.get(), crypto::Encryptor::CTR, ""); |
+ encryptor.SetCounter(std::string(counter, kAesNonceSize)); |
+ encryptor.Encrypt(report, &ciphertext); |
+ |
+ // Compute HMAC-SHA256(nonce || ciphertext). |
+ std::string hmac_input = std::string(counter, kAesNonceSize) + ciphertext; |
+ crypto::HMAC hmac(crypto::HMAC::SHA256); |
+ bool init_result = hmac.Init(hmac_key); |
agl
2015/03/05 19:22:25
why does |init_result| and |hmac_result| exist? Yo
|
+ if (!init_result) { |
+ LOG(ERROR) << "Failed to initialize HMAC."; |
+ return init_result; |
+ } |
+ |
+ unsigned char digest[hmac.DigestLength()]; |
agl
2015/03/05 19:22:25
Aren't variable-length arrays a compiler extension
|
+ bool hmac_result = hmac.Sign(hmac_input, digest, sizeof(digest)); |
+ if (!hmac_result) { |
+ LOG(ERROR) << "Failed to compute HMAC."; |
+ return hmac_result; |
+ } |
+ |
+ encrypted_report.set_encrypted_report(ciphertext); |
+ encrypted_report.set_server_public_key(server_public_key_version); |
+ encrypted_report.set_client_public_key( |
+ std::string((char*)public_key, crypto::curve25519::kBytes)); |
+ encrypted_report.set_nonce(std::string(counter, kAesNonceSize)); |
+ encrypted_report.set_mac(std::string((char*)digest, sizeof(digest))); |
+ encrypted_report.set_algorithm( |
+ EncryptedCertLoggerRequest::ECDH_AES_CTR_128_HMAC_SHA256); |
+ return true; |
+} |
+ |
static std::string BuildReport(const std::string& hostname, |
const net::SSLInfo& ssl_info) { |
CertLoggerRequest request; |
@@ -77,24 +161,37 @@ void ChromeFraudulentCertificateReporter::SendReport( |
ReportType type, |
const std::string& hostname, |
const net::SSLInfo& ssl_info) { |
+ // We do silent/automatic reporting ONLY for Google properties. For other |
+ // domains (when we start supporting that), we will ask for user permission. |
+ if (type == REPORT_TYPE_PIN_VIOLATION && |
+ !net::TransportSecurityState::IsGooglePinnedProperty(hostname)) { |
+ return; |
+ } |
+ |
+ std::string report = BuildReport(hostname, ssl_info); |
+ |
if (type == REPORT_TYPE_EXTENDED_REPORTING) { |
// TODO(estark): Double-check that the user is opted in. |
// TODO(estark): Temporarily, since there is no upload endpoint, just log |
// the information. |
- LOG(ERROR) << "SSL report for " << hostname << ":\n" |
- << BuildReport(hostname, ssl_info) << "\n\n"; |
- return; |
- } |
+ LOG(ERROR) << "SSL report for " << hostname << ":\n" << report << "\n\n"; |
+ |
+ EncryptedCertLoggerRequest encrypted_request; |
+ bool result = EncryptSerializedReport( |
+ kServerPublicKey, kServerPublicKeyVersion, report, encrypted_request); |
+ if (!result) { |
+ LOG(ERROR) << "Failed to encrypt serialized report."; |
+ return; |
+ } |
+ |
+ std::string encrypted_report; |
+ encrypted_request.SerializeToString(&encrypted_report); |
+ LOG(ERROR) << "Encrypted: " << encrypted_report; |
- // We do silent/automatic reporting ONLY for Google properties. For other |
- // domains (when we start supporting that), we will ask for user permission. |
- if (!net::TransportSecurityState::IsGooglePinnedProperty(hostname)) { |
return; |
} |
- std::string report = BuildReport(hostname, ssl_info); |
- |
scoped_ptr<net::URLRequest> url_request = |
CreateURLRequest(request_context_, pinning_violation_upload_url_); |
url_request->set_method("POST"); |