chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h"

#include <stdint.h>

#include <functional>
#include <memory>
#include <optional>
#include <set>
#include <utility>

#include "base/base64.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/values_util.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/content_settings_pref_provider.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/security_interstitials/core/pref_names.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/hash_value.h"
#include "net/cert/x509_certificate.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "url/gurl.h"

namespace {

#if BUILDFLAG(IS_ANDROID)
StatefulSSLHostStateDelegate::RecurrentInterstitialMode
    kRecurrentInterstitialDefaultMode =
        StatefulSSLHostStateDelegate::RecurrentInterstitialMode::PREF;
#else
StatefulSSLHostStateDelegate::RecurrentInterstitialMode
    kRecurrentInterstitialDefaultMode =;
#endif

// The number of times an error must recur before the recurrent error message is
// shown.
constexpr int kRecurrentInterstitialDefaultThreshold =;

// If "mode" is "pref", a pref stores the time at which each error most recently
// occurred, and the recurrent error message is shown if the error has recurred
// more than the threshold number of times with the most recent instance being
// less than |kRecurrentInterstitialResetTimeParam| seconds in the past. The
// default is 3 days.
constexpr int kRecurrentInterstitialDefaultResetTime =;  // 3 days in seconds

// The default expiration for certificate error bypasses is one week.
const uint64_t kDefaultCertErrorBypassExpirationInSeconds =604800);

// The expiration for HTTPS-First Mode bypasses is 15 days.
const uint64_t kHTTPSFirstModeBypassExpirationInSeconds =1296000);

// Keys for the per-site error + certificate finger to judgment content
// settings map.
const char kSSLCertDecisionCertErrorMapKey[] =;
const char kSSLCertDecisionExpirationTimeKey[] =;
const char kSSLCertDecisionVersionKey[] =;

const int kDefaultSSLCertDecisionVersion =;

// Records a new occurrence of |error|. The occurrence is stored in the
// recurrent interstitial pref, which keeps track of the most recent timestamps
// at which each error type occurred (up to the |threshold| most recent
// instances per error). The list is reset if the clock has gone backwards at
// any point.
void UpdateRecurrentInterstitialPref(PrefService* pref_service,
                                     base::Clock* clock,
                                     int error,
                                     int threshold) {}

bool DoesRecurrentInterstitialPrefMeetThreshold(PrefService* pref_service,
                                                base::Clock* clock,
                                                int error,
                                                int threshold,
                                                int error_reset_time) {}

// All SSL decisions are per host (and are shared arcoss schemes), so this
// canonicalizes all hosts into a secure scheme GURL to use with content
// settings. The returned GURL will be the passed in host with an empty path and
// https:// as the scheme.
GURL GetSecureGURLForHost(const std::string& host) {}

std::string GetKey(const net::X509Certificate& cert, int error) {}

bool HostFilterToPatternFilter(
    base::OnceCallback<bool(const std::string&)> host_filter,
    const ContentSettingsPattern& primary_pattern,
    const ContentSettingsPattern& secondary_pattern) {}

}  // namespace

StatefulSSLHostStateDelegate::StatefulSSLHostStateDelegate(
    content::BrowserContext* browser_context,
    PrefService* pref_service,
    HostContentSettingsMap* host_content_settings_map)
    :{}

StatefulSSLHostStateDelegate::~StatefulSSLHostStateDelegate() = default;

void StatefulSSLHostStateDelegate::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {}

void StatefulSSLHostStateDelegate::AllowCert(
    const std::string& host,
    const net::X509Certificate& cert,
    int error,
    content::StoragePartition* storage_partition) {}

void StatefulSSLHostStateDelegate::Clear(
    base::RepeatingCallback<bool(const std::string&)> host_filter) {}

content::SSLHostStateDelegate::CertJudgment
StatefulSSLHostStateDelegate::QueryPolicy(
    const std::string& host,
    const net::X509Certificate& cert,
    int error,
    content::StoragePartition* storage_partition) {}

void StatefulSSLHostStateDelegate::HostRanInsecureContent(
    const std::string& host,
    int child_id,
    InsecureContentType content_type) {}

bool StatefulSSLHostStateDelegate::DidHostRunInsecureContent(
    const std::string& host,
    int child_id,
    InsecureContentType content_type) {}

void StatefulSSLHostStateDelegate::AllowHttpForHost(
    const std::string& host,
    content::StoragePartition* storage_partition) {}

bool StatefulSSLHostStateDelegate::IsHttpAllowedForHost(
    const std::string& host,
    content::StoragePartition* storage_partition) {}

void StatefulSSLHostStateDelegate::SetHttpsEnforcementForHost(
    const std::string& host,
    bool enforced,
    content::StoragePartition* storage_partition) {}

bool StatefulSSLHostStateDelegate::IsHttpsEnforcedForUrl(
    const GURL& url,
    content::StoragePartition* storage_partition) {}

std::set<GURL> StatefulSSLHostStateDelegate::GetHttpsEnforcedHosts(
    content::StoragePartition* storage_partition) const {}

void StatefulSSLHostStateDelegate::ClearHttpsOnlyModeAllowlist() {}

void StatefulSSLHostStateDelegate::ClearHttpsEnforcelist() {}

void StatefulSSLHostStateDelegate::RevokeUserAllowExceptions(
    const std::string& host) {}

bool StatefulSSLHostStateDelegate::HasAllowException(
    const std::string& host,
    content::StoragePartition* storage_partition) {}

bool StatefulSSLHostStateDelegate::HasAllowExceptionForAnyHost(
    content::StoragePartition* storage_partition) {}

bool StatefulSSLHostStateDelegate::HasCertAllowExceptionForAnyHost(
    content::StoragePartition* storage_partition) {}

bool StatefulSSLHostStateDelegate::IsHttpAllowedForAnyHost(
    content::StoragePartition* storage_partition) {}

// TODO(jww): This will revoke all of the decisions in the browser context.
// However, the networking stack actually keeps track of its own list of
// exceptions per-HttpNetworkTransaction in the SSLConfig structure (see the
// allowed_bad_certs Vector in net/ssl/ssl_config.h). This dual-tracking of
// exceptions introduces a problem where the browser context can revoke a
// certificate, but if a transaction reuses a cached version of the SSLConfig
// (probably from a pooled socket), it may bypass the intestitial layer.
//
// Over time, the cached versions should expire and it should converge on
// showing the interstitial. We probably need to introduce into the networking
// stack a way revoke SSLConfig's allowed_bad_certs lists per socket.
//
// For now, RevokeUserAllowExceptionsHard is our solution for the rare case
// where it is necessary to revoke the preferences immediately. It does so by
// flushing idle sockets, thus it is a big hammer and should be wielded with
// extreme caution as it can have a big, negative impact on network performance.
void StatefulSSLHostStateDelegate::RevokeUserAllowExceptionsHard(
    const std::string& host) {}

void StatefulSSLHostStateDelegate::DidDisplayErrorPage(int error) {}

bool StatefulSSLHostStateDelegate::HasSeenRecurrentErrors(int error) const {}

void StatefulSSLHostStateDelegate::ResetRecurrentErrorCountForTesting() {}

bool StatefulSSLHostStateDelegate::
    HttpsFirstBalancedModeSuppressedForTesting() {}

void StatefulSSLHostStateDelegate::
    SetHttpsFirstBalancedModeSuppressedForTesting(bool suppressed) {}

void StatefulSSLHostStateDelegate::SetClockForTesting(
    std::unique_ptr<base::Clock> clock) {}

void StatefulSSLHostStateDelegate::SetRecurrentInterstitialThresholdForTesting(
    int threshold) {}

void StatefulSSLHostStateDelegate::SetRecurrentInterstitialModeForTesting(
    StatefulSSLHostStateDelegate::RecurrentInterstitialMode mode) {}

void StatefulSSLHostStateDelegate::SetRecurrentInterstitialResetTimeForTesting(
    int reset) {}

int StatefulSSLHostStateDelegate::GetRecurrentInterstitialThreshold() const {}

int StatefulSSLHostStateDelegate::GetRecurrentInterstitialResetTime() const {}

StatefulSSLHostStateDelegate::RecurrentInterstitialMode
StatefulSSLHostStateDelegate::GetRecurrentInterstitialMode() const {}

bool StatefulSSLHostStateDelegate::HasCertAllowException(
    const std::string& host,
    content::StoragePartition* storage_partition) {}

// This helper function gets the dictionary of certificate fingerprints to
// errors of certificates that have been accepted by the user from the content
// dictionary that has been passed in. The returned pointer is owned by the the
// argument dict that is passed in.
//
// If create_entries is set to |DO_NOT_CREATE_DICTIONARY_ENTRIES|,
// GetValidCertDecisionsDict will return nullptr if there is anything invalid
// about the setting, such as an invalid version or invalid value types (in
// addition to there not being any values in the dictionary). If create_entries
// is set to |CREATE_DICTIONARY_ENTRIES|, if no dictionary is found or the
// decisions are expired, a new dictionary will be created.
base::Value::Dict* StatefulSSLHostStateDelegate::GetValidCertDecisionsDict(
    CreateDictionaryEntriesDisposition create_entries,
    base::Value::Dict& dict) {}