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

Unified Diff: components/gcm_driver/crypto/gcm_encryption_provider.cc

Issue 2892033002: Enable support for draft-ietf-webpush-encryption-08 (Closed)
Patch Set: Enable support for draft-ietf-webpush-encryption-08 Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: components/gcm_driver/crypto/gcm_encryption_provider.cc
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider.cc b/components/gcm_driver/crypto/gcm_encryption_provider.cc
index c9c7183ebe6757f330e4a032ef45508eb76b0323..6a4bdc5f43b3ca1b676696cc37d5e9208e93816a 100644
--- a/components/gcm_driver/crypto/gcm_encryption_provider.cc
+++ b/components/gcm_driver/crypto/gcm_encryption_provider.cc
@@ -13,6 +13,7 @@
#include "components/gcm_driver/crypto/encryption_header_parsers.h"
#include "components/gcm_driver/crypto/gcm_key_store.h"
#include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
+#include "components/gcm_driver/crypto/message_payload_parser.h"
#include "components/gcm_driver/crypto/p256_key_util.h"
#include "components/gcm_driver/crypto/proto/gcm_encryption_data.pb.h"
@@ -21,8 +22,12 @@ namespace gcm {
namespace {
const char kEncryptionProperty[] = "encryption";
+const char kContentEncodingProperty[] = "content-encoding";
const char kCryptoKeyProperty[] = "crypto-key";
+// Content coding name defined by ietf-httpbis-encryption-encoding.
+const char kContentCodingAes128Gcm[] = "aes128gcm";
+
// Directory in the GCM Store in which the encryption database will be stored.
const base::FilePath::CharType kEncryptionDirectoryName[] =
FILE_PATH_LITERAL("Encryption");
@@ -34,8 +39,10 @@ std::string GCMEncryptionProvider::ToDecryptionResultDetailsString(
switch (result) {
case DECRYPTION_RESULT_UNENCRYPTED:
return "Message was not encrypted";
- case DECRYPTION_RESULT_DECRYPTED:
- return "Message decrypted";
+ case DECRYPTION_RESULT_DECRYPTED_DRAFT_03:
+ return "Message decrypted (draft 03)";
+ case DECRYPTION_RESULT_DECRYPTED_DRAFT_08:
+ return "Message decrypted (draft 08)";
case DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER:
return "Invalid format for the Encryption header";
case DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER:
@@ -46,6 +53,8 @@ std::string GCMEncryptionProvider::ToDecryptionResultDetailsString(
return "The shared secret cannot be derived from the keying material";
case DECRYPTION_RESULT_INVALID_PAYLOAD:
return "AES-GCM decryption failed";
+ case DECRYPTION_RESULT_INVALID_BINARY_HEADER:
+ return "The message's binary header could not be parsed.";
}
NOTREACHED();
@@ -97,6 +106,14 @@ void GCMEncryptionProvider::RemoveEncryptionInfo(
bool GCMEncryptionProvider::IsEncryptedMessage(const IncomingMessage& message)
const {
+ // Messages that explicitly specify their content coding to be "aes128gcm"
+ // indicate that they use draft-ietf-webpush-encryption-08.
+ auto content_encoding_iter = message.data.find(kContentEncodingProperty);
+ if (content_encoding_iter != message.data.end() &&
+ content_encoding_iter->second == kContentCodingAes128Gcm) {
+ return true;
+ }
+
// The Web Push protocol requires the encryption and crypto-key properties to
// be set, and the raw_data field to be populated with the payload.
if (message.data.find(kEncryptionProperty) == message.data.end() ||
@@ -116,77 +133,110 @@ void GCMEncryptionProvider::DecryptMessage(
return;
}
- // IsEncryptedMessage() verifies that both the Encryption and Crypto-Key HTTP
- // headers have been provided for the |message|.
- const auto& encryption_header = message.data.find(kEncryptionProperty);
- const auto& crypto_key_header = message.data.find(kCryptoKeyProperty);
+ std::string salt, public_key, ciphertext;
+ GCMMessageCryptographer::Version version;
+ uint32_t record_size;
+
+ auto content_encoding_iter = message.data.find(kContentEncodingProperty);
+ if (content_encoding_iter != message.data.end() &&
+ content_encoding_iter->second == kContentCodingAes128Gcm) {
+ // The message follows encryption per draft-ietf-webpush-encryption-08. Use
+ // the binary header of the message to derive the values.
+
+ MessagePayloadParser parser(message.raw_data);
+ if (!parser.IsValid()) {
+ DLOG(ERROR) << "Unable to parse the message's binary header";
+ callback.Run(DECRYPTION_RESULT_INVALID_BINARY_HEADER, IncomingMessage());
+ return;
+ }
- DCHECK(encryption_header != message.data.end());
- DCHECK(crypto_key_header != message.data.end());
+ salt = parser.salt();
+ public_key = parser.public_key();
+ record_size = parser.record_size();
+ ciphertext = parser.ciphertext();
+ version = GCMMessageCryptographer::Version::DRAFT_08;
+
+ } else {
+ // The message follows encryption per draft-ietf-webpush-encryption-03. Use
+ // the Encryption and Crypto-Key header values to derive the values.
+
+ const auto& encryption_header = message.data.find(kEncryptionProperty);
+ DCHECK(encryption_header != message.data.end());
+
+ const auto& crypto_key_header = message.data.find(kCryptoKeyProperty);
+ DCHECK(crypto_key_header != message.data.end());
+
+ EncryptionHeaderIterator encryption_header_iterator(
+ encryption_header->second.begin(), encryption_header->second.end());
+ if (!encryption_header_iterator.GetNext()) {
+ DLOG(ERROR) << "Unable to parse the value of the Encryption header";
+ callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER,
+ IncomingMessage());
+ return;
+ }
- EncryptionHeaderIterator encryption_header_iterator(
- encryption_header->second.begin(), encryption_header->second.end());
- if (!encryption_header_iterator.GetNext()) {
- DLOG(ERROR) << "Unable to parse the value of the Encryption header";
- callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER,
- IncomingMessage());
- return;
- }
+ if (encryption_header_iterator.salt().size() !=
+ GCMMessageCryptographer::kSaltSize) {
+ DLOG(ERROR) << "Invalid values supplied in the Encryption header";
+ callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER,
+ IncomingMessage());
+ return;
+ }
- if (encryption_header_iterator.salt().size() !=
- GCMMessageCryptographer::kSaltSize) {
- DLOG(ERROR) << "Invalid values supplied in the Encryption header";
- callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER,
- IncomingMessage());
- return;
- }
+ salt = encryption_header_iterator.salt();
+ record_size = encryption_header_iterator.rs();
- CryptoKeyHeaderIterator crypto_key_header_iterator(
- crypto_key_header->second.begin(), crypto_key_header->second.end());
- if (!crypto_key_header_iterator.GetNext()) {
- DLOG(ERROR) << "Unable to parse the value of the Crypto-Key header";
- callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER,
- IncomingMessage());
- return;
- }
+ CryptoKeyHeaderIterator crypto_key_header_iterator(
+ crypto_key_header->second.begin(), crypto_key_header->second.end());
+ if (!crypto_key_header_iterator.GetNext()) {
+ DLOG(ERROR) << "Unable to parse the value of the Crypto-Key header";
+ callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER,
+ IncomingMessage());
+ return;
+ }
- // Ignore values that don't include the "dh" property. When using VAPID, it is
- // valid for the application server to supply multiple values.
- while (crypto_key_header_iterator.dh().empty() &&
- crypto_key_header_iterator.GetNext()) {}
+ // Ignore values that don't include the "dh" property. When using VAPID, it
+ // is valid for the application server to supply multiple values.
+ while (crypto_key_header_iterator.dh().empty() &&
+ crypto_key_header_iterator.GetNext()) {
+ }
- bool valid_crypto_key_header = false;
- std::string dh;
+ bool valid_crypto_key_header = false;
- if (!crypto_key_header_iterator.dh().empty()) {
- dh = crypto_key_header_iterator.dh();
- valid_crypto_key_header = true;
+ if (!crypto_key_header_iterator.dh().empty()) {
+ public_key = crypto_key_header_iterator.dh();
+ valid_crypto_key_header = true;
- // Guard against the "dh" property being included more than once.
- while (crypto_key_header_iterator.GetNext()) {
- if (crypto_key_header_iterator.dh().empty())
- continue;
+ // Guard against the "dh" property being included more than once.
+ while (crypto_key_header_iterator.GetNext()) {
+ if (crypto_key_header_iterator.dh().empty())
+ continue;
- valid_crypto_key_header = false;
- break;
+ valid_crypto_key_header = false;
+ break;
+ }
}
- }
- if (!valid_crypto_key_header) {
- DLOG(ERROR) << "Invalid values supplied in the Crypto-Key header";
- callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER,
- IncomingMessage());
- return;
+ if (!valid_crypto_key_header) {
+ DLOG(ERROR) << "Invalid values supplied in the Crypto-Key header";
+ callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER,
+ IncomingMessage());
+ return;
+ }
+
+ ciphertext = message.raw_data;
+ version = GCMMessageCryptographer::Version::DRAFT_03;
}
// Use |fallback_to_empty_authorized_entity|, since this message might have
// been sent to either an InstanceID token or a non-InstanceID registration.
- key_store_->GetKeys(app_id, message.sender_id /* authorized_entity */,
- true /* fallback_to_empty_authorized_entity */,
- base::Bind(&GCMEncryptionProvider::DecryptMessageWithKey,
- weak_ptr_factory_.GetWeakPtr(), message,
- callback, encryption_header_iterator.salt(),
- dh, encryption_header_iterator.rs()));
+ key_store_->GetKeys(
+ app_id, message.sender_id /* authorized_entity */,
+ true /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMEncryptionProvider::DecryptMessageWithKey,
+ weak_ptr_factory_.GetWeakPtr(), message.collapse_key,
+ message.sender_id, std::move(salt), std::move(public_key),
+ record_size, std::move(ciphertext), version, callback));
}
void GCMEncryptionProvider::DidGetEncryptionInfo(
@@ -222,11 +272,14 @@ void GCMEncryptionProvider::DidCreateEncryptionInfo(
}
void GCMEncryptionProvider::DecryptMessageWithKey(
- const IncomingMessage& message,
- const MessageCallback& callback,
+ const std::string& collapse_key,
+ const std::string& sender_id,
const std::string& salt,
- const std::string& dh,
- uint64_t rs,
+ const std::string& public_key,
+ uint32_t record_size,
+ const std::string& ciphertext,
+ GCMMessageCryptographer::Version version,
+ const MessageCallback& callback,
const KeyPair& pair,
const std::string& auth_secret) {
if (!pair.IsInitialized()) {
@@ -238,8 +291,8 @@ void GCMEncryptionProvider::DecryptMessageWithKey(
DCHECK_EQ(KeyPair::ECDH_P256, pair.type());
std::string shared_secret;
- if (!ComputeSharedP256Secret(pair.private_key(), pair.public_key_x509(), dh,
- &shared_secret)) {
+ if (!ComputeSharedP256Secret(pair.private_key(), pair.public_key_x509(),
+ public_key, &shared_secret)) {
DLOG(ERROR) << "Unable to calculate the shared secret.";
callback.Run(DECRYPTION_RESULT_INVALID_SHARED_SECRET, IncomingMessage());
return;
@@ -247,19 +300,19 @@ void GCMEncryptionProvider::DecryptMessageWithKey(
std::string plaintext;
- GCMMessageCryptographer cryptographer(
- GCMMessageCryptographer::Version::DRAFT_03);
+ GCMMessageCryptographer cryptographer(version);
- if (!cryptographer.Decrypt(pair.public_key(), dh, shared_secret, auth_secret,
- salt, message.raw_data, rs, &plaintext)) {
+ if (!cryptographer.Decrypt(pair.public_key(), public_key, shared_secret,
+ auth_secret, salt, ciphertext, record_size,
+ &plaintext)) {
DLOG(ERROR) << "Unable to decrypt the incoming data.";
callback.Run(DECRYPTION_RESULT_INVALID_PAYLOAD, IncomingMessage());
return;
}
IncomingMessage decrypted_message;
- decrypted_message.collapse_key = message.collapse_key;
- decrypted_message.sender_id = message.sender_id;
+ decrypted_message.collapse_key = collapse_key;
+ decrypted_message.sender_id = sender_id;
decrypted_message.raw_data.swap(plaintext);
decrypted_message.decrypted = true;
@@ -267,7 +320,10 @@ void GCMEncryptionProvider::DecryptMessageWithKey(
// to make sure that we don't end up in an infinite decryption loop.
DCHECK_EQ(0u, decrypted_message.data.size());
- callback.Run(DECRYPTION_RESULT_DECRYPTED, decrypted_message);
+ callback.Run(version == GCMMessageCryptographer::Version::DRAFT_03
+ ? DECRYPTION_RESULT_DECRYPTED_DRAFT_03
+ : DECRYPTION_RESULT_DECRYPTED_DRAFT_08,
+ decrypted_message);
}
} // namespace gcm

Powered by Google App Engine
This is Rietveld 408576698