summaryrefslogtreecommitdiffstats
path: root/sync/internal_api/sync_encryption_handler_impl.h
blob: 6cbf74ed8b60b4c5a2f445edbb3275e2f30e18ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SYNC_INTERNAL_API_SYNC_ENCRYPTION_HANDLER_IMPL_H_
#define SYNC_INTERNAL_API_SYNC_ENCRYPTION_HANDLER_IMPL_H_

#include <string>

#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "sync/base/sync_export.h"
#include "sync/internal_api/public/sync_encryption_handler.h"
#include "sync/syncable/nigori_handler.h"
#include "sync/util/cryptographer.h"

namespace syncer {

class Encryptor;
struct UserShare;
class WriteNode;
class WriteTransaction;

// Sync encryption handler implementation.
//
// This class acts as the respository of all sync encryption state, and handles
// encryption related changes/queries coming from both the chrome side and
// the sync side (via NigoriHandler). It is capable of modifying all sync data
// (re-encryption), updating the encrypted types, changing the encryption keys,
// and creating/receiving nigori node updates.
//
// The class should live as long as the directory itself in order to ensure
// any data read/written is properly decrypted/encrypted.
//
// Note: See sync_encryption_handler.h for a description of the chrome visible
// methods and what they do, and nigori_handler.h for a description of the
// sync methods.
// All methods are non-thread-safe and should only be called from the sync
// thread unless explicitly noted otherwise.
class SYNC_EXPORT_PRIVATE SyncEncryptionHandlerImpl
    : public SyncEncryptionHandler,
      public syncable::NigoriHandler {
 public:
  SyncEncryptionHandlerImpl(
      UserShare* user_share,
      Encryptor* encryptor,
      const std::string& restored_key_for_bootstrapping,
      const std::string& restored_keystore_key_for_bootstrapping);
  virtual ~SyncEncryptionHandlerImpl();

  // SyncEncryptionHandler implementation.
  virtual void AddObserver(Observer* observer) override;
  virtual void RemoveObserver(Observer* observer) override;
  virtual void Init() override;
  virtual void SetEncryptionPassphrase(const std::string& passphrase,
                                       bool is_explicit) override;
  virtual void SetDecryptionPassphrase(const std::string& passphrase) override;
  virtual void EnableEncryptEverything() override;
  virtual bool EncryptEverythingEnabled() const override;
  virtual PassphraseType GetPassphraseType() const override;

  // NigoriHandler implementation.
  // Note: all methods are invoked while the caller holds a transaction.
  virtual void ApplyNigoriUpdate(
      const sync_pb::NigoriSpecifics& nigori,
      syncable::BaseTransaction* const trans) override;
  virtual void UpdateNigoriFromEncryptedTypes(
      sync_pb::NigoriSpecifics* nigori,
      syncable::BaseTransaction* const trans) const override;
  virtual bool NeedKeystoreKey(
      syncable::BaseTransaction* const trans) const override;
  virtual bool SetKeystoreKeys(
      const google::protobuf::RepeatedPtrField<google::protobuf::string>& keys,
      syncable::BaseTransaction* const trans) override;
  // Can be called from any thread.
  virtual ModelTypeSet GetEncryptedTypes(
      syncable::BaseTransaction* const trans) const override;

  // Unsafe getters. Use only if sync is not up and running and there is no risk
  // of other threads calling this.
  Cryptographer* GetCryptographerUnsafe();
  ModelTypeSet GetEncryptedTypesUnsafe();

  bool MigratedToKeystore();
  base::Time migration_time() const;
  base::Time custom_passphrase_time() const;

 private:
  friend class SyncEncryptionHandlerImplTest;
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           NigoriEncryptionTypes);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           EncryptEverythingExplicit);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           EncryptEverythingImplicit);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           UnknownSensitiveTypes);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           GetKeystoreDecryptor);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           ReceiveMigratedNigoriKeystorePass);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           ReceiveUmigratedNigoriAfterMigration);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           ReceiveOldMigratedNigori);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           SetKeystoreAfterReceivingMigratedNigori);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           SetCustomPassAfterMigration);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           SetCustomPassAfterMigrationNoKeystoreKey);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           SetImplicitPassAfterMigrationNoKeystoreKey);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           MigrateOnEncryptEverythingKeystorePassphrase);
  FRIEND_TEST_ALL_PREFIXES(SyncEncryptionHandlerImplTest,
                           ReceiveMigratedNigoriWithOldPassphrase);

  // Container for members that require thread safety protection.  All members
  // that can be accessed from more than one thread should be held here and
  // accessed via UnlockVault(..) and UnlockVaultMutable(..), which enforce
  // that a transaction is held.
  struct Vault {
    Vault(Encryptor* encryptor, ModelTypeSet encrypted_types);
    ~Vault();

    // Sync's cryptographer. Used for encrypting and decrypting sync data.
    Cryptographer cryptographer;
    // The set of types that require encryption.
    ModelTypeSet encrypted_types;

   private:
    DISALLOW_COPY_AND_ASSIGN(Vault);
  };

  // Iterate over all encrypted types ensuring each entry is properly encrypted.
  void ReEncryptEverything(WriteTransaction* trans);

  // Apply a nigori update. Updates internal and cryptographer state.
  // Returns true on success, false if |nigori| was incompatible, and the
  // nigori node must be corrected.
  // Note: must be called from within a transaction.
  bool ApplyNigoriUpdateImpl(const sync_pb::NigoriSpecifics& nigori,
                             syncable::BaseTransaction* const trans);

  // Wrapper around WriteEncryptionStateToNigori that creates a new write
  // transaction.
  void RewriteNigori();

  // Write the current encryption state into the nigori node. This includes
  // the encrypted types/encrypt everything state, as well as the keybag/
  // explicit passphrase state (if the cryptographer is ready).
  void WriteEncryptionStateToNigori(WriteTransaction* trans);

  // Updates local encrypted types from |nigori|.
  // Returns true if the local set of encrypted types either matched or was
  // a subset of that in |nigori|. Returns false if the local state already
  // had stricter encryption than |nigori|, and the nigori node needs to be
  // updated with the newer encryption state.
  // Note: must be called from within a transaction.
  bool UpdateEncryptedTypesFromNigori(
      const sync_pb::NigoriSpecifics& nigori,
      syncable::BaseTransaction* const trans);

  // TODO(zea): make these public and have them replace SetEncryptionPassphrase
  // and SetDecryptionPassphrase.
  // Helper methods for handling passphrases once keystore migration has taken
  // place.
  //
  // Sets a new custom passphrase. Should only be called if a custom passphrase
  // is not already set.
  // Triggers OnPassphraseAccepted on success, OnPassphraseRequired if a custom
  // passphrase already existed.
  void SetCustomPassphrase(const std::string& passphrase,
                           WriteTransaction* trans,
                           WriteNode* nigori_node);
  // Decrypt the encryption keybag using a user provided passphrase.
  // Should only be called if the current passphrase is a frozen implicit
  // passphrase or a custom passphrase.
  // Triggers OnPassphraseAccepted on success, OnPassphraseRequired on failure.
  void DecryptPendingKeysWithExplicitPassphrase(const std::string& passphrase,
                                                WriteTransaction* trans,
                                                WriteNode* nigori_node);

  // The final step of SetEncryptionPassphrase and SetDecryptionPassphrase that
  // notifies observers of the result of the set passphrase operation, updates
  // the nigori node, and does re-encryption.
  // |success|: true if the operation was successful and false otherwise. If
  //            success == false, we send an OnPassphraseRequired notification.
  // |bootstrap_token|: used to inform observers if the cryptographer's
  //                    bootstrap token was updated.
  // |is_explicit|: used to differentiate between a custom passphrase (true) and
  //                a GAIA passphrase that is implicitly used for encryption
  //                (false).
  // |trans| and |nigori_node|: used to access data in the cryptographer.
  void FinishSetPassphrase(bool success,
                           const std::string& bootstrap_token,
                           WriteTransaction* trans,
                           WriteNode* nigori_node);

  // Merges the given set of encrypted types with the existing set and emits a
  // notification if necessary.
  // Note: must be called from within a transaction.
  void MergeEncryptedTypes(ModelTypeSet new_encrypted_types,
                           syncable::BaseTransaction* const trans);

  // Helper methods for ensuring transactions are held when accessing
  // |vault_unsafe_|.
  Vault* UnlockVaultMutable(syncable::BaseTransaction* const trans);
  const Vault& UnlockVault(syncable::BaseTransaction* const trans) const;

  // Helper method for determining if migration of a nigori node should be
  // triggered or not.
  // Conditions for triggering migration:
  // 1. Cryptographer has no pending keys
  // 2. Nigori node isn't already properly migrated or we need to rotate keys.
  // 3. Keystore key is available.
  // Note: if the nigori node is migrated but has an invalid state, will return
  // true (e.g. node has KEYSTORE_PASSPHRASE, local is CUSTOM_PASSPHRASE).
  bool ShouldTriggerMigration(const sync_pb::NigoriSpecifics& nigori,
                              const Cryptographer& cryptographer) const;

  // Performs the actual migration of the |nigori_node| to support keystore
  // encryption iff ShouldTriggerMigration(..) returns true.
  bool AttemptToMigrateNigoriToKeystore(WriteTransaction* trans,
                                        WriteNode* nigori_node);

  // Fill |encrypted_blob| with the keystore decryptor token if
  // |encrypted_blob|'s contents didn't already contain the key.
  // The keystore decryptor token is the serialized current default encryption
  // key, encrypted with the keystore key.
  bool GetKeystoreDecryptor(
      const Cryptographer& cryptographer,
      const std::string& keystore_key,
      sync_pb::EncryptedData* encrypted_blob);

  // Helper method for installing the keys encrypted in |encryption_keybag|
  // into |cryptographer|.
  // Returns true on success, false if we were unable to install the keybag.
  // Will not update the default key.
  bool AttemptToInstallKeybag(const sync_pb::EncryptedData& keybag,
                              bool update_default,
                              Cryptographer* cryptographer);

  // Helper method for decrypting pending keys with the keystore bootstrap.
  // If successful, the default will become the key encrypted in the keystore
  // bootstrap, and will return true. Else will return false.
  bool DecryptPendingKeysWithKeystoreKey(
      const std::string& keystore_key,
      const sync_pb::EncryptedData& keystore_bootstrap,
      Cryptographer* cryptographer);

  // Helper to enable encrypt everything, notifying observers if necessary.
  // Will not perform re-encryption.
  void EnableEncryptEverythingImpl(syncable::BaseTransaction* const trans);

  // If an explicit passphrase is in use, returns the time at which it was set
  // (if known). Else return base::Time().
  base::Time GetExplicitPassphraseTime() const;

  base::ThreadChecker thread_checker_;

  ObserverList<SyncEncryptionHandler::Observer> observers_;

  // The current user share (for creating transactions).
  UserShare* user_share_;

  // Container for all data that can be accessed from multiple threads. Do not
  // access this object directly. Instead access it via UnlockVault(..) and
  // UnlockVaultMutable(..).
  Vault vault_unsafe_;

  // Sync encryption state that is only modified and accessed from the sync
  // thread.
  // Whether all current and future types should be encrypted.
  bool encrypt_everything_;
  // The current state of the passphrase required to decrypt the encryption
  // keys stored in the nigori node.
  PassphraseType passphrase_type_;

  // The current keystore key provided by the server.
  std::string keystore_key_;

  // The set of old keystore keys. Every time a key rotation occurs, the server
  // sends down all previous keystore keys as well as the new key. We preserve
  // the old keys so that when we re-encrypt we can ensure they're all added to
  // the keybag (and to detect that a key rotation has occurred).
  std::vector<std::string> old_keystore_keys_;

  // The number of times we've automatically (i.e. not via SetPassphrase or
  // conflict resolver) updated the nigori's encryption keys in this chrome
  // instantiation.
  int nigori_overwrite_count_;

  // The time the nigori was migrated to support keystore encryption.
  base::Time migration_time_;

  // The time the custom passphrase was set for this account. Not valid
  // if there is no custom passphrase or the custom passphrase was set
  // before support for this field was added.
  base::Time custom_passphrase_time_;

  base::WeakPtrFactory<SyncEncryptionHandlerImpl> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(SyncEncryptionHandlerImpl);
};

}  // namespace syncer

#endif  // SYNC_INTERNAL_API_PUBLIC_SYNC_ENCRYPTION_HANDLER_IMPL_H_