File: encryption_helper.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (255 lines) | stat: -rw-r--r-- 10,116 bytes parent folder | download | duplicates (3)
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
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/test/integration/encryption_helper.h"

#include <string>
#include <vector>

#include "base/base64.h"
#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "components/sync/base/passphrase_enums.h"
#include "components/sync/service/sync_client.h"
#include "components/sync/service/sync_service_impl.h"
#include "google_apis/gaia/gaia_id.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace encryption_helper {

namespace {

GURL GetFakeTrustedVaultRetrievalURL(
    const net::test_server::EmbeddedTestServer& test_server,
    const GaiaId& gaia_id,
    const std::vector<uint8_t>& encryption_key,
    int encryption_key_version) {
  // encryption_keys_retrieval.html would populate encryption key to
  // TrustedVaultService service upon loading. Key is provided as part of URL
  // and needs to be encoded with Base64, because it is binary.
  const std::string base64_encoded_key = base::Base64Encode(encryption_key);
  return test_server.GetURL(base::StringPrintf(
      "/sync/encryption_keys_retrieval.html?gaia=%s&key=%s&key_version=%d",
      gaia_id.ToString().c_str(), base64_encoded_key.c_str(),
      encryption_key_version));
}

GURL GetFakeTrustedVaultRecoverabilityURL(
    const net::test_server::EmbeddedTestServer& test_server,
    const GaiaId& gaia_id,
    const std::vector<uint8_t>& public_key) {
  // encryption_keys_recoverability.html would populate `public_key` to
  // TrustedVaultService upon loading. Key is provided as part of URL and needs
  // to be encoded with Base64, because it is binary.
  const std::string base64_encoded_public_key = base::Base64Encode(public_key);
  return test_server.GetURL(base::StringPrintf(
      "/sync/encryption_keys_recoverability.html?%s#%s",
      gaia_id.ToString().c_str(), base64_encoded_public_key.c_str()));
}

// Helper function to install server redirects in the test HTTP server.
std::unique_ptr<net::test_server::HttpResponse> HttpServerRedirect(
    const GURL& from_prefix,
    const GURL& to,
    const net::test_server::HttpRequest& request) {
  if (!base::StartsWith(request.GetURL().spec(), from_prefix.spec())) {
    return nullptr;
  }
  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
  http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
  http_response->AddCustomHeader("Location", to.spec());
  http_response->set_content_type("text/html");
  http_response->set_content(base::StringPrintf(
      "<html><head></head><body>Redirecting to %s</body></html>",
      to.spec().c_str()));
  return http_response;
}

}  // namespace

void SetupFakeTrustedVaultPages(
    const GaiaId& gaia_id,
    const std::vector<uint8_t>& trusted_vault_key,
    int trusted_vault_key_version,
    const std::vector<uint8_t>& recovery_method_public_key,
    net::test_server::EmbeddedTestServer* test_server) {
  CHECK(test_server);
  // Note that this needs to be installed before the analogous below for
  // retrieval, because they share prefix.
  const GURL recoverability_url = GetFakeTrustedVaultRecoverabilityURL(
      *test_server, gaia_id, recovery_method_public_key);
  test_server->RegisterRequestHandler(base::BindRepeating(
      &HttpServerRedirect,
      /*from_prefix=*/
      GaiaUrls::GetInstance()
          ->signin_chrome_sync_keys_recoverability_degraded_url(),
      /*to=*/recoverability_url));

  const GURL retrieval_url = GetFakeTrustedVaultRetrievalURL(
      *test_server, gaia_id, trusted_vault_key, trusted_vault_key_version);
  test_server->RegisterRequestHandler(base::BindRepeating(
      &HttpServerRedirect,
      /*from_prefix=*/
      GaiaUrls::GetInstance()->signin_chrome_sync_keys_retrieval_url(),
      /*to=*/retrieval_url));
}

}  // namespace encryption_helper

ServerPassphraseTypeChecker::ServerPassphraseTypeChecker(
    syncer::PassphraseType expected_passphrase_type)
    : expected_passphrase_type_(expected_passphrase_type) {}

bool ServerPassphraseTypeChecker::IsExitConditionSatisfied(std::ostream* os) {
  *os << "Waiting for a Nigori node with the proper passphrase type to become "
         "available on the server.";

  std::vector<sync_pb::SyncEntity> nigori_entities =
      fake_server()->GetPermanentSyncEntitiesByDataType(syncer::NIGORI);
  EXPECT_LE(nigori_entities.size(), 1U);
  return !nigori_entities.empty() &&
         syncer::ProtoPassphraseInt32ToEnum(
             nigori_entities[0].specifics().nigori().passphrase_type()) ==
             expected_passphrase_type_;
}

ServerCrossUserSharingPublicKeyChangedChecker::
    ServerCrossUserSharingPublicKeyChangedChecker(
        const std::string& previous_public_key)
    : previous_public_key_(previous_public_key) {}

bool ServerCrossUserSharingPublicKeyChangedChecker::IsExitConditionSatisfied(
    std::ostream* os) {
  *os << "Waiting for a Nigori node with a new cross-user sharing public key"
      << " available on the server";

  std::vector<sync_pb::SyncEntity> nigori_entities =
      fake_server()->GetPermanentSyncEntitiesByDataType(syncer::NIGORI);
  EXPECT_LE(nigori_entities.size(), 1U);
  return !nigori_entities.empty() &&
         nigori_entities[0]
                 .specifics()
                 .nigori()
                 .cross_user_sharing_public_key()
                 .x25519_public_key() != previous_public_key_;
}

ServerNigoriKeyNameChecker::ServerNigoriKeyNameChecker(
    const std::string& expected_key_name)
    : expected_key_name_(expected_key_name) {}

bool ServerNigoriKeyNameChecker::IsExitConditionSatisfied(std::ostream* os) {
  std::vector<sync_pb::SyncEntity> nigori_entities =
      fake_server()->GetPermanentSyncEntitiesByDataType(syncer::NIGORI);
  DCHECK_EQ(nigori_entities.size(), 1U);

  const std::string given_key_name =
      nigori_entities[0].specifics().nigori().encryption_keybag().key_name();

  *os << "Waiting for a Nigori node with proper key bag encryption key name ("
      << expected_key_name_ << ") to become available on the server."
      << "The server key bag encryption key name is " << given_key_name << ".";
  return given_key_name == expected_key_name_;
}

PassphraseRequiredChecker::PassphraseRequiredChecker(
    syncer::SyncServiceImpl* service)
    : SingleClientStatusChangeChecker(service) {}

bool PassphraseRequiredChecker::IsExitConditionSatisfied(std::ostream* os) {
  *os << "Checking whether passhrase is required";
  return service()->IsEngineInitialized() &&
         service()->GetUserSettings()->IsPassphraseRequired();
}

PassphraseAcceptedChecker::PassphraseAcceptedChecker(
    syncer::SyncServiceImpl* service)
    : SingleClientStatusChangeChecker(service) {}

bool PassphraseAcceptedChecker::IsExitConditionSatisfied(std::ostream* os) {
  *os << "Checking whether passhrase is accepted";
  switch (service()->GetUserSettings()->GetPassphraseType().value_or(
      syncer::PassphraseType::kKeystorePassphrase)) {
    case syncer::PassphraseType::kKeystorePassphrase:
    case syncer::PassphraseType::kTrustedVaultPassphrase:
      return false;
    // With kImplicitPassphrase the user needs to enter the passphrase even
    // though it's not treated as an explicit passphrase.
    case syncer::PassphraseType::kImplicitPassphrase:
    case syncer::PassphraseType::kFrozenImplicitPassphrase:
    case syncer::PassphraseType::kCustomPassphrase:
      break;
  }
  return service()->IsEngineInitialized() &&
         !service()->GetUserSettings()->IsPassphraseRequired();
}

PassphraseTypeChecker::PassphraseTypeChecker(
    syncer::SyncServiceImpl* service,
    syncer::PassphraseType expected_passphrase_type)
    : SingleClientStatusChangeChecker(service),
      expected_passphrase_type_(expected_passphrase_type) {}

bool PassphraseTypeChecker::IsExitConditionSatisfied(std::ostream* os) {
  *os << "Checking expected passhrase type";
  return service()->GetUserSettings()->GetPassphraseType() ==
         expected_passphrase_type_;
}

TrustedVaultKeyRequiredStateChecker::TrustedVaultKeyRequiredStateChecker(
    syncer::SyncServiceImpl* service,
    bool desired_state)
    : SingleClientStatusChangeChecker(service), desired_state_(desired_state) {}

bool TrustedVaultKeyRequiredStateChecker::IsExitConditionSatisfied(
    std::ostream* os) {
  *os << "Waiting until trusted vault keys are " +
             std::string(desired_state_ ? "required" : "not required");
  return service()
             ->GetUserSettings()
             ->IsTrustedVaultKeyRequiredForPreferredDataTypes() ==
         desired_state_;
}

TrustedVaultKeysChangedStateChecker::TrustedVaultKeysChangedStateChecker(
    syncer::SyncServiceImpl* service)
    : service_(service) {
  service->GetSyncClientForTest()->GetTrustedVaultClient()->AddObserver(this);
}

TrustedVaultKeysChangedStateChecker::~TrustedVaultKeysChangedStateChecker() {
  service_->GetSyncClientForTest()->GetTrustedVaultClient()->RemoveObserver(
      this);
}

bool TrustedVaultKeysChangedStateChecker::IsExitConditionSatisfied(
    std::ostream* os) {
  *os << "Waiting for trusted vault keys change";
  return keys_changed_;
}

void TrustedVaultKeysChangedStateChecker::OnTrustedVaultKeysChanged() {
  keys_changed_ = true;
  CheckExitCondition();
}

void TrustedVaultKeysChangedStateChecker::
    OnTrustedVaultRecoverabilityChanged() {}

TrustedVaultRecoverabilityDegradedStateChecker::
    TrustedVaultRecoverabilityDegradedStateChecker(
        syncer::SyncServiceImpl* service,
        bool degraded)
    : SingleClientStatusChangeChecker(service), degraded_(degraded) {}

bool TrustedVaultRecoverabilityDegradedStateChecker::IsExitConditionSatisfied(
    std::ostream* os) {
  *os << "Waiting until trusted vault recoverability degraded state is "
      << degraded_;
  return service()->GetUserSettings()->IsTrustedVaultRecoverabilityDegraded() ==
         degraded_;
}