gcm_encryption_provider.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/gcm_driver/crypto/gcm_encryption_provider.h"
  5. #include <memory>
  6. #include "base/base64.h"
  7. #include "base/big_endian.h"
  8. #include "base/bind.h"
  9. #include "base/logging.h"
  10. #include "base/strings/strcat.h"
  11. #include "components/gcm_driver/common/gcm_message.h"
  12. #include "components/gcm_driver/crypto/encryption_header_parsers.h"
  13. #include "components/gcm_driver/crypto/gcm_decryption_result.h"
  14. #include "components/gcm_driver/crypto/gcm_encryption_result.h"
  15. #include "components/gcm_driver/crypto/gcm_key_store.h"
  16. #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
  17. #include "components/gcm_driver/crypto/message_payload_parser.h"
  18. #include "components/gcm_driver/crypto/p256_key_util.h"
  19. #include "components/gcm_driver/crypto/proto/gcm_encryption_data.pb.h"
  20. #include "crypto/ec_private_key.h"
  21. #include "crypto/random.h"
  22. namespace gcm {
  23. namespace {
  24. const char kEncryptionProperty[] = "encryption";
  25. const char kCryptoKeyProperty[] = "crypto-key";
  26. const char kInternalRawData[] = "_googRawData";
  27. // Directory in the GCM Store in which the encryption database will be stored.
  28. const base::FilePath::CharType kEncryptionDirectoryName[] =
  29. FILE_PATH_LITERAL("Encryption");
  30. IncomingMessage CreateMessageWithId(const std::string& message_id) {
  31. IncomingMessage message;
  32. message.message_id = message_id;
  33. return message;
  34. }
  35. } // namespace
  36. GCMEncryptionProvider::GCMEncryptionProvider() {}
  37. GCMEncryptionProvider::~GCMEncryptionProvider() = default;
  38. // static
  39. const char GCMEncryptionProvider::kContentEncodingProperty[] =
  40. "content-encoding";
  41. // static
  42. const char GCMEncryptionProvider::kContentCodingAes128Gcm[] = "aes128gcm";
  43. void GCMEncryptionProvider::Init(
  44. const base::FilePath& store_path,
  45. const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) {
  46. DCHECK(!key_store_);
  47. base::FilePath encryption_store_path = store_path;
  48. // |store_path| can be empty in tests, which means that the database should
  49. // be created in memory rather than on-disk.
  50. if (!store_path.empty())
  51. encryption_store_path = store_path.Append(kEncryptionDirectoryName);
  52. key_store_ = std::make_unique<GCMKeyStore>(encryption_store_path,
  53. blocking_task_runner);
  54. }
  55. void GCMEncryptionProvider::GetEncryptionInfo(
  56. const std::string& app_id,
  57. const std::string& authorized_entity,
  58. EncryptionInfoCallback callback) {
  59. DCHECK(key_store_);
  60. key_store_->GetKeys(
  61. app_id, authorized_entity,
  62. false /* fallback_to_empty_authorized_entity */,
  63. base::BindOnce(&GCMEncryptionProvider::DidGetEncryptionInfo,
  64. weak_ptr_factory_.GetWeakPtr(), app_id, authorized_entity,
  65. std::move(callback)));
  66. }
  67. void GCMEncryptionProvider::DidGetEncryptionInfo(
  68. const std::string& app_id,
  69. const std::string& authorized_entity,
  70. EncryptionInfoCallback callback,
  71. std::unique_ptr<crypto::ECPrivateKey> key,
  72. const std::string& auth_secret) {
  73. if (!key) {
  74. key_store_->CreateKeys(
  75. app_id, authorized_entity,
  76. base::BindOnce(&GCMEncryptionProvider::DidCreateEncryptionInfo,
  77. weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
  78. return;
  79. }
  80. std::string public_key;
  81. const bool success = GetRawPublicKey(*key, &public_key);
  82. DCHECK(success);
  83. std::move(callback).Run(public_key, auth_secret);
  84. }
  85. void GCMEncryptionProvider::RemoveEncryptionInfo(
  86. const std::string& app_id,
  87. const std::string& authorized_entity,
  88. base::OnceClosure callback) {
  89. DCHECK(key_store_);
  90. key_store_->RemoveKeys(app_id, authorized_entity, std::move(callback));
  91. }
  92. bool GCMEncryptionProvider::IsEncryptedMessage(
  93. const IncomingMessage& message) const {
  94. // Messages that explicitly specify their content coding to be "aes128gcm"
  95. // indicate that they use draft-ietf-webpush-encryption-08.
  96. auto content_encoding_iter = message.data.find(kContentEncodingProperty);
  97. if (content_encoding_iter != message.data.end() &&
  98. content_encoding_iter->second == kContentCodingAes128Gcm) {
  99. return true;
  100. }
  101. // The Web Push protocol requires the encryption and crypto-key properties to
  102. // be set, and the raw_data field to be populated with the payload.
  103. if (message.data.find(kEncryptionProperty) == message.data.end() ||
  104. message.data.find(kCryptoKeyProperty) == message.data.end())
  105. return false;
  106. return message.raw_data.size() > 0;
  107. }
  108. void GCMEncryptionProvider::DecryptMessage(const std::string& app_id,
  109. const IncomingMessage& message,
  110. DecryptMessageCallback callback) {
  111. DCHECK(key_store_);
  112. if (!IsEncryptedMessage(message)) {
  113. std::move(callback).Run(GCMDecryptionResult::UNENCRYPTED, message);
  114. return;
  115. }
  116. std::string salt, public_key, ciphertext;
  117. GCMMessageCryptographer::Version version;
  118. uint32_t record_size;
  119. auto content_encoding_iter = message.data.find(kContentEncodingProperty);
  120. if (content_encoding_iter != message.data.end() &&
  121. content_encoding_iter->second == kContentCodingAes128Gcm) {
  122. // The message follows encryption per draft-ietf-webpush-encryption-08. Use
  123. // the binary header of the message to derive the values.
  124. auto parser = std::make_unique<MessagePayloadParser>(message.raw_data);
  125. if (!parser->IsValid()) {
  126. // Attempt to parse base64 encoded internal raw data.
  127. auto raw_data_iter = message.data.find(kInternalRawData);
  128. std::string raw_data;
  129. if (raw_data_iter == message.data.end() ||
  130. !base::Base64Decode(raw_data_iter->second, &raw_data) ||
  131. !(parser = std::make_unique<MessagePayloadParser>(raw_data))
  132. ->IsValid()) {
  133. DLOG(ERROR) << "Unable to parse the message's binary header";
  134. std::move(callback).Run(parser->GetFailureReason(),
  135. CreateMessageWithId(message.message_id));
  136. return;
  137. }
  138. }
  139. salt = parser->salt();
  140. public_key = parser->public_key();
  141. record_size = parser->record_size();
  142. ciphertext = parser->ciphertext();
  143. version = GCMMessageCryptographer::Version::DRAFT_08;
  144. } else {
  145. // The message follows encryption per draft-ietf-webpush-encryption-03. Use
  146. // the Encryption and Crypto-Key header values to derive the values.
  147. const auto& encryption_header = message.data.find(kEncryptionProperty);
  148. DCHECK(encryption_header != message.data.end());
  149. const auto& crypto_key_header = message.data.find(kCryptoKeyProperty);
  150. DCHECK(crypto_key_header != message.data.end());
  151. EncryptionHeaderIterator encryption_header_iterator(
  152. encryption_header->second.begin(), encryption_header->second.end());
  153. if (!encryption_header_iterator.GetNext()) {
  154. DLOG(ERROR) << "Unable to parse the value of the Encryption header";
  155. std::move(callback).Run(GCMDecryptionResult::INVALID_ENCRYPTION_HEADER,
  156. CreateMessageWithId(message.message_id));
  157. return;
  158. }
  159. if (encryption_header_iterator.salt().size() !=
  160. GCMMessageCryptographer::kSaltSize) {
  161. DLOG(ERROR) << "Invalid values supplied in the Encryption header";
  162. std::move(callback).Run(GCMDecryptionResult::INVALID_ENCRYPTION_HEADER,
  163. CreateMessageWithId(message.message_id));
  164. return;
  165. }
  166. salt = encryption_header_iterator.salt();
  167. record_size = encryption_header_iterator.rs();
  168. CryptoKeyHeaderIterator crypto_key_header_iterator(
  169. crypto_key_header->second.begin(), crypto_key_header->second.end());
  170. if (!crypto_key_header_iterator.GetNext()) {
  171. DLOG(ERROR) << "Unable to parse the value of the Crypto-Key header";
  172. std::move(callback).Run(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER,
  173. CreateMessageWithId(message.message_id));
  174. return;
  175. }
  176. // Ignore values that don't include the "dh" property. When using VAPID, it
  177. // is valid for the application server to supply multiple values.
  178. while (crypto_key_header_iterator.dh().empty() &&
  179. crypto_key_header_iterator.GetNext()) {
  180. }
  181. bool valid_crypto_key_header = false;
  182. if (!crypto_key_header_iterator.dh().empty()) {
  183. public_key = crypto_key_header_iterator.dh();
  184. valid_crypto_key_header = true;
  185. // Guard against the "dh" property being included more than once.
  186. while (crypto_key_header_iterator.GetNext()) {
  187. if (crypto_key_header_iterator.dh().empty())
  188. continue;
  189. valid_crypto_key_header = false;
  190. break;
  191. }
  192. }
  193. if (!valid_crypto_key_header) {
  194. DLOG(ERROR) << "Invalid values supplied in the Crypto-Key header";
  195. std::move(callback).Run(GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER,
  196. CreateMessageWithId(message.message_id));
  197. return;
  198. }
  199. ciphertext = message.raw_data;
  200. version = GCMMessageCryptographer::Version::DRAFT_03;
  201. }
  202. // Use |fallback_to_empty_authorized_entity|, since this message might have
  203. // been sent to either an InstanceID token or a non-InstanceID registration.
  204. key_store_->GetKeys(
  205. app_id, message.sender_id /* authorized_entity */,
  206. true /* fallback_to_empty_authorized_entity */,
  207. base::BindOnce(&GCMEncryptionProvider::DecryptMessageWithKey,
  208. weak_ptr_factory_.GetWeakPtr(), message.message_id,
  209. message.collapse_key, message.sender_id, std::move(salt),
  210. std::move(public_key), record_size, std::move(ciphertext),
  211. version, std::move(callback)));
  212. } // namespace gcm
  213. void GCMEncryptionProvider::EncryptMessage(const std::string& app_id,
  214. const std::string& authorized_entity,
  215. const std::string& p256dh,
  216. const std::string& auth_secret,
  217. const std::string& message,
  218. EncryptMessageCallback callback) {
  219. DCHECK(key_store_);
  220. key_store_->GetKeys(
  221. app_id, authorized_entity,
  222. false /* fallback_to_empty_authorized_entity */,
  223. base::BindOnce(&GCMEncryptionProvider::EncryptMessageWithKey,
  224. weak_ptr_factory_.GetWeakPtr(), app_id, authorized_entity,
  225. p256dh, auth_secret, message, std::move(callback)));
  226. }
  227. void GCMEncryptionProvider::DidCreateEncryptionInfo(
  228. EncryptionInfoCallback callback,
  229. std::unique_ptr<crypto::ECPrivateKey> key,
  230. const std::string& auth_secret) {
  231. if (!key) {
  232. std::move(callback).Run(std::string() /* p256dh */,
  233. std::string() /* auth_secret */);
  234. return;
  235. }
  236. std::string public_key;
  237. const bool success = GetRawPublicKey(*key, &public_key);
  238. DCHECK(success);
  239. std::move(callback).Run(public_key, auth_secret);
  240. }
  241. void GCMEncryptionProvider::DecryptMessageWithKey(
  242. const std::string& message_id,
  243. const std::string& collapse_key,
  244. const std::string& sender_id,
  245. const std::string& salt,
  246. const std::string& public_key,
  247. uint32_t record_size,
  248. const std::string& ciphertext,
  249. GCMMessageCryptographer::Version version,
  250. DecryptMessageCallback callback,
  251. std::unique_ptr<crypto::ECPrivateKey> key,
  252. const std::string& auth_secret) {
  253. if (!key) {
  254. DLOG(ERROR) << "Unable to retrieve the keys for the incoming message.";
  255. std::move(callback).Run(GCMDecryptionResult::NO_KEYS,
  256. CreateMessageWithId(message_id));
  257. return;
  258. }
  259. std::string shared_secret;
  260. if (!ComputeSharedP256Secret(*key, public_key, &shared_secret)) {
  261. DLOG(ERROR) << "Unable to calculate the shared secret.";
  262. std::move(callback).Run(GCMDecryptionResult::INVALID_SHARED_SECRET,
  263. CreateMessageWithId(message_id));
  264. return;
  265. }
  266. std::string plaintext;
  267. GCMMessageCryptographer cryptographer(version);
  268. std::string exported_public_key;
  269. const bool success = GetRawPublicKey(*key, &exported_public_key);
  270. DCHECK(success);
  271. if (!cryptographer.Decrypt(exported_public_key, public_key, shared_secret,
  272. auth_secret, salt, ciphertext, record_size,
  273. &plaintext)) {
  274. DLOG(ERROR) << "Unable to decrypt the incoming data.";
  275. std::move(callback).Run(GCMDecryptionResult::INVALID_PAYLOAD,
  276. CreateMessageWithId(message_id));
  277. return;
  278. }
  279. IncomingMessage decrypted_message;
  280. decrypted_message.message_id = message_id;
  281. decrypted_message.collapse_key = collapse_key;
  282. decrypted_message.sender_id = sender_id;
  283. decrypted_message.raw_data.swap(plaintext);
  284. decrypted_message.decrypted = true;
  285. // There must be no data associated with the decrypted message at this point,
  286. // to make sure that we don't end up in an infinite decryption loop.
  287. DCHECK_EQ(0u, decrypted_message.data.size());
  288. std::move(callback).Run(version == GCMMessageCryptographer::Version::DRAFT_03
  289. ? GCMDecryptionResult::DECRYPTED_DRAFT_03
  290. : GCMDecryptionResult::DECRYPTED_DRAFT_08,
  291. std::move(decrypted_message));
  292. }
  293. void GCMEncryptionProvider::EncryptMessageWithKey(
  294. const std::string& app_id,
  295. const std::string& authorized_entity,
  296. const std::string& p256dh,
  297. const std::string& auth_secret,
  298. const std::string& message,
  299. EncryptMessageCallback callback,
  300. std::unique_ptr<crypto::ECPrivateKey> key,
  301. const std::string& sender_auth_secret) {
  302. if (!key) {
  303. DLOG(ERROR) << "Unable to retrieve the keys for the outgoing message.";
  304. std::move(callback).Run(GCMEncryptionResult::NO_KEYS, std::string());
  305. return;
  306. }
  307. // Creates a cryptographically secure salt of |salt_size| octets in size,
  308. // and calculate the shared secret for the message.
  309. std::string salt;
  310. crypto::RandBytes(base::WriteInto(&salt, 16 + 1), 16);
  311. std::string shared_secret;
  312. if (!ComputeSharedP256Secret(*key, p256dh, &shared_secret)) {
  313. DLOG(ERROR) << "Unable to calculate the shared secret.";
  314. std::move(callback).Run(GCMEncryptionResult::INVALID_SHARED_SECRET,
  315. std::string());
  316. return;
  317. }
  318. size_t record_size;
  319. std::string ciphertext;
  320. GCMMessageCryptographer cryptographer(
  321. GCMMessageCryptographer::Version::DRAFT_08);
  322. std::string sender_public_key;
  323. bool success = GetRawPublicKey(*key, &sender_public_key);
  324. DCHECK(success);
  325. if (!cryptographer.Encrypt(p256dh, sender_public_key, shared_secret,
  326. auth_secret, salt, message, &record_size,
  327. &ciphertext)) {
  328. DLOG(ERROR) << "Unable to encrypt the incoming data.";
  329. std::move(callback).Run(GCMEncryptionResult::ENCRYPTION_FAILED,
  330. std::string());
  331. return;
  332. }
  333. // Construct encryption header.
  334. uint32_t rs = record_size;
  335. char rs_buf[sizeof(rs)];
  336. base::WriteBigEndian(rs_buf, rs);
  337. std::string rs_str(std::begin(rs_buf), std::end(rs_buf));
  338. uint8_t key_length = sender_public_key.size();
  339. char key_length_buf[sizeof(key_length)];
  340. base::WriteBigEndian(key_length_buf, key_length);
  341. std::string key_length_str(std::begin(key_length_buf),
  342. std::end(key_length_buf));
  343. std::string payload = base::StrCat(
  344. {salt, rs_str, key_length_str, sender_public_key, ciphertext});
  345. std::move(callback).Run(GCMEncryptionResult::ENCRYPTED_DRAFT_08,
  346. std::move(payload));
  347. }
  348. } // namespace gcm