Add net error code for self-signed certs on local network URLs
This adds (behind a new, default disabled feature flag) a new net error code (ERR_CERT_SELF_SIGNED_LOCAL_NETWORK), which is returned for certificate errors when the certificate is self-signed, and is being used on a local network URL (either an RFC 1918 IP, or a URL that ends in .local). This is step one towards implementing go/betterselfsigned, for now this only results in the regular SSL interstitial being triggered. Bug: 394119724 Change-Id: I62850128c250358071cc0693526b23c2677647cf Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6226147 Commit-Queue: Carlos IL <carlosil@chromium.org> Reviewed-by: Matt Mueller <mattm@chromium.org> Cr-Commit-Position: refs/heads/main@{#1424804}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
859865d196
commit
9f2a0256c7
components
net
@ -26,6 +26,7 @@ int IsCertErrorFatal(int cert_error) {
|
|||||||
case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
|
case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
|
||||||
case net::ERR_CERT_SYMANTEC_LEGACY:
|
case net::ERR_CERT_SYMANTEC_LEGACY:
|
||||||
case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED:
|
case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED:
|
||||||
|
case net::ERR_CERT_SELF_SIGNED_LOCAL_NETWORK:
|
||||||
return false;
|
return false;
|
||||||
case net::ERR_CERT_CONTAINS_ERRORS:
|
case net::ERR_CERT_CONTAINS_ERRORS:
|
||||||
case net::ERR_CERT_REVOKED:
|
case net::ERR_CERT_REVOKED:
|
||||||
|
@ -100,6 +100,7 @@ ErrorInfo ErrorInfo::CreateError(ErrorType error_type,
|
|||||||
case CERT_KNOWN_INTERCEPTION_BLOCKED:
|
case CERT_KNOWN_INTERCEPTION_BLOCKED:
|
||||||
case CERT_AUTHORITY_INVALID:
|
case CERT_AUTHORITY_INVALID:
|
||||||
case CERT_SYMANTEC_LEGACY:
|
case CERT_SYMANTEC_LEGACY:
|
||||||
|
case CERT_SELF_SIGNED_LOCAL_NETWORK:
|
||||||
details =
|
details =
|
||||||
l10n_util::GetStringFUTF16(IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS,
|
l10n_util::GetStringFUTF16(IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS,
|
||||||
UTF8ToUTF16(request_url.host()));
|
UTF8ToUTF16(request_url.host()));
|
||||||
@ -235,6 +236,8 @@ ErrorInfo::ErrorType ErrorInfo::NetErrorToErrorType(int net_error) {
|
|||||||
return CERT_SYMANTEC_LEGACY;
|
return CERT_SYMANTEC_LEGACY;
|
||||||
case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED:
|
case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED:
|
||||||
return CERT_KNOWN_INTERCEPTION_BLOCKED;
|
return CERT_KNOWN_INTERCEPTION_BLOCKED;
|
||||||
|
case net::ERR_CERT_SELF_SIGNED_LOCAL_NETWORK:
|
||||||
|
return CERT_SELF_SIGNED_LOCAL_NETWORK;
|
||||||
default:
|
default:
|
||||||
NOTREACHED();
|
NOTREACHED();
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ class ErrorInfo {
|
|||||||
CERT_KNOWN_INTERCEPTION_BLOCKED = 17,
|
CERT_KNOWN_INTERCEPTION_BLOCKED = 17,
|
||||||
LEGACY_TLS = 18,
|
LEGACY_TLS = 18,
|
||||||
CERT_NON_UNIQUE_NAME = 19,
|
CERT_NON_UNIQUE_NAME = 19,
|
||||||
|
CERT_SELF_SIGNED_LOCAL_NETWORK = 20,
|
||||||
END_OF_ENUM
|
END_OF_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -708,4 +708,8 @@ BASE_FEATURE(kUseCertTransparencyAwareApiForOsCertVerify,
|
|||||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||||
#endif // BUILDFLAG(IS_ANDROID)
|
#endif // BUILDFLAG(IS_ANDROID)
|
||||||
|
|
||||||
|
BASE_FEATURE(kSelfSignedLocalNetworkInterstitial,
|
||||||
|
"SelfSignedLocalNetworkInterstitial",
|
||||||
|
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||||
|
|
||||||
} // namespace net::features
|
} // namespace net::features
|
||||||
|
@ -725,6 +725,10 @@ NET_EXPORT BASE_DECLARE_FEATURE(kExcludeLargeBodyReports);
|
|||||||
NET_EXPORT BASE_DECLARE_FEATURE(kUseCertTransparencyAwareApiForOsCertVerify);
|
NET_EXPORT BASE_DECLARE_FEATURE(kUseCertTransparencyAwareApiForOsCertVerify);
|
||||||
#endif // BUILDFLAG(IS_ANDROID)
|
#endif // BUILDFLAG(IS_ANDROID)
|
||||||
|
|
||||||
|
// Enables a special interstitial for self signed cert errors in local network
|
||||||
|
// URLs.
|
||||||
|
NET_EXPORT BASE_DECLARE_FEATURE(kSelfSignedLocalNetworkInterstitial);
|
||||||
|
|
||||||
} // namespace net::features
|
} // namespace net::features
|
||||||
|
|
||||||
#endif // NET_BASE_FEATURES_H_
|
#endif // NET_BASE_FEATURES_H_
|
||||||
|
@ -564,13 +564,17 @@ NET_ERROR(CERT_KNOWN_INTERCEPTION_BLOCKED, -217)
|
|||||||
// -218 was SSL_OBSOLETE_VERSION which is not longer used. TLS 1.0/1.1 instead
|
// -218 was SSL_OBSOLETE_VERSION which is not longer used. TLS 1.0/1.1 instead
|
||||||
// cause SSL_VERSION_OR_CIPHER_MISMATCH now.
|
// cause SSL_VERSION_OR_CIPHER_MISMATCH now.
|
||||||
|
|
||||||
|
// The certificate is self signed and it's being used for either an RFC1918 IP
|
||||||
|
// literal URL, or a url ending in .local.
|
||||||
|
NET_ERROR(CERT_SELF_SIGNED_LOCAL_NETWORK, -219)
|
||||||
|
|
||||||
// Add new certificate error codes here.
|
// Add new certificate error codes here.
|
||||||
//
|
//
|
||||||
// Update the value of CERT_END whenever you add a new certificate error
|
// Update the value of CERT_END whenever you add a new certificate error
|
||||||
// code.
|
// code.
|
||||||
|
|
||||||
// The value immediately past the last certificate error code.
|
// The value immediately past the last certificate error code.
|
||||||
NET_ERROR(CERT_END, -219)
|
NET_ERROR(CERT_END, -220)
|
||||||
|
|
||||||
// The URL is invalid.
|
// The URL is invalid.
|
||||||
NET_ERROR(INVALID_URL, -300)
|
NET_ERROR(INVALID_URL, -300)
|
||||||
|
@ -29,6 +29,7 @@ TEST(NetErrorsTest, IsCertificateError) {
|
|||||||
EXPECT_TRUE(IsCertificateError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM));
|
EXPECT_TRUE(IsCertificateError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM));
|
||||||
EXPECT_TRUE(IsCertificateError(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN));
|
EXPECT_TRUE(IsCertificateError(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN));
|
||||||
EXPECT_TRUE(IsCertificateError(ERR_CERT_KNOWN_INTERCEPTION_BLOCKED));
|
EXPECT_TRUE(IsCertificateError(ERR_CERT_KNOWN_INTERCEPTION_BLOCKED));
|
||||||
|
EXPECT_TRUE(IsCertificateError(ERR_CERT_SELF_SIGNED_LOCAL_NETWORK));
|
||||||
|
|
||||||
// Negative tests.
|
// Negative tests.
|
||||||
EXPECT_FALSE(IsCertificateError(ERR_SSL_PROTOCOL_ERROR));
|
EXPECT_FALSE(IsCertificateError(ERR_SSL_PROTOCOL_ERROR));
|
||||||
@ -42,7 +43,7 @@ TEST(NetErrorsTest, IsCertificateError) {
|
|||||||
|
|
||||||
// Trigger a failure whenever ERR_CERT_END is changed, forcing developers to
|
// Trigger a failure whenever ERR_CERT_END is changed, forcing developers to
|
||||||
// update this test.
|
// update this test.
|
||||||
EXPECT_EQ(ERR_CERT_END, -219)
|
EXPECT_EQ(ERR_CERT_END, -220)
|
||||||
<< "It looks like you added a new certificate error code ("
|
<< "It looks like you added a new certificate error code ("
|
||||||
<< ErrorToString(ERR_CERT_END + 1)
|
<< ErrorToString(ERR_CERT_END + 1)
|
||||||
<< ").\n"
|
<< ").\n"
|
||||||
|
@ -353,6 +353,14 @@ std::string CanonicalizeHost(std::string_view host,
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
std::string CanonicalizeHostSupportsBareIPV6(std::string_view host,
|
||||||
|
url::CanonHostInfo* host_info) {
|
||||||
|
const std::string host_or_ip = host.find(':') != std::string::npos
|
||||||
|
? base::StrCat({"[", host, "]"})
|
||||||
|
: std::string(host);
|
||||||
|
return CanonicalizeHost(host_or_ip, host_info);
|
||||||
|
}
|
||||||
|
|
||||||
std::string CanonicalizeHost(std::string_view host,
|
std::string CanonicalizeHost(std::string_view host,
|
||||||
url::CanonHostInfo* host_info) {
|
url::CanonHostInfo* host_info) {
|
||||||
return CanonicalizeHost(host, /*is_file_scheme=*/false, host_info);
|
return CanonicalizeHost(host, /*is_file_scheme=*/false, host_info);
|
||||||
|
@ -167,6 +167,12 @@ NET_EXPORT std::string GetSuperdomain(std::string_view domain);
|
|||||||
NET_EXPORT bool IsSubdomainOf(std::string_view subdomain,
|
NET_EXPORT bool IsSubdomainOf(std::string_view subdomain,
|
||||||
std::string_view superdomain);
|
std::string_view superdomain);
|
||||||
|
|
||||||
|
// Wrapper for CanonicalizeHost that allows using a bare IPV6. If |host| is
|
||||||
|
// not IPV6, this is equivalent to CanonicalizeHost.
|
||||||
|
NET_EXPORT std::string CanonicalizeHostSupportsBareIPV6(
|
||||||
|
std::string_view host,
|
||||||
|
url::CanonHostInfo* host_info);
|
||||||
|
|
||||||
// Canonicalizes |host| and returns it. Also fills |host_info| with
|
// Canonicalizes |host| and returns it. Also fills |host_info| with
|
||||||
// IP address information. |host_info| must not be NULL.
|
// IP address information. |host_info| must not be NULL.
|
||||||
// Canonicalization will follow the host parsing rules for a non-file
|
// Canonicalization will follow the host parsing rules for a non-file
|
||||||
|
@ -25,10 +25,15 @@ int MapCertStatusToNetError(CertStatus cert_status) {
|
|||||||
return ERR_CERT_KNOWN_INTERCEPTION_BLOCKED;
|
return ERR_CERT_KNOWN_INTERCEPTION_BLOCKED;
|
||||||
if (cert_status & CERT_STATUS_REVOKED)
|
if (cert_status & CERT_STATUS_REVOKED)
|
||||||
return ERR_CERT_REVOKED;
|
return ERR_CERT_REVOKED;
|
||||||
if (cert_status & CERT_STATUS_AUTHORITY_INVALID)
|
if (cert_status & CERT_STATUS_AUTHORITY_INVALID &&
|
||||||
|
!(cert_status & CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK)) {
|
||||||
return ERR_CERT_AUTHORITY_INVALID;
|
return ERR_CERT_AUTHORITY_INVALID;
|
||||||
|
}
|
||||||
if (cert_status & CERT_STATUS_COMMON_NAME_INVALID)
|
if (cert_status & CERT_STATUS_COMMON_NAME_INVALID)
|
||||||
return ERR_CERT_COMMON_NAME_INVALID;
|
return ERR_CERT_COMMON_NAME_INVALID;
|
||||||
|
if (cert_status & CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK) {
|
||||||
|
return ERR_CERT_SELF_SIGNED_LOCAL_NETWORK;
|
||||||
|
}
|
||||||
if (cert_status & CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED)
|
if (cert_status & CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED)
|
||||||
return ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
|
return ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
|
||||||
if (cert_status & CERT_STATUS_SYMANTEC_LEGACY)
|
if (cert_status & CERT_STATUS_SYMANTEC_LEGACY)
|
||||||
|
@ -45,3 +45,4 @@ CERT_STATUS_FLAG(CERTIFICATE_TRANSPARENCY_REQUIRED, 1 << 24)
|
|||||||
CERT_STATUS_FLAG(SYMANTEC_LEGACY, 1 << 25)
|
CERT_STATUS_FLAG(SYMANTEC_LEGACY, 1 << 25)
|
||||||
CERT_STATUS_FLAG(KNOWN_INTERCEPTION_BLOCKED, 1 << 26)
|
CERT_STATUS_FLAG(KNOWN_INTERCEPTION_BLOCKED, 1 << 26)
|
||||||
// Bit 27 was CERT_STATUS_LEGACY_TLS.
|
// Bit 27 was CERT_STATUS_LEGACY_TLS.
|
||||||
|
CERT_STATUS_FLAG(SELF_SIGNED_LOCAL_NETWORK, 1 << 28)
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#include "base/feature_list.h"
|
#include "base/feature_list.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/memory/raw_ptr.h"
|
#include "base/memory/raw_ptr.h"
|
||||||
|
#include "base/strings/strcat.h"
|
||||||
|
#include "base/strings/string_util.h"
|
||||||
#include "base/time/time.h"
|
#include "base/time/time.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "components/network_time/time_tracker/time_tracker.h"
|
#include "components/network_time/time_tracker/time_tracker.h"
|
||||||
@ -20,6 +22,7 @@
|
|||||||
#include "net/base/features.h"
|
#include "net/base/features.h"
|
||||||
#include "net/base/ip_address.h"
|
#include "net/base/ip_address.h"
|
||||||
#include "net/base/net_errors.h"
|
#include "net/base/net_errors.h"
|
||||||
|
#include "net/base/url_util.h"
|
||||||
#include "net/cert/cert_net_fetcher.h"
|
#include "net/cert/cert_net_fetcher.h"
|
||||||
#include "net/cert/cert_status_flags.h"
|
#include "net/cert/cert_status_flags.h"
|
||||||
#include "net/cert/cert_verifier.h"
|
#include "net/cert/cert_verifier.h"
|
||||||
@ -49,6 +52,7 @@
|
|||||||
#include "third_party/boringssl/src/pki/trust_store.h"
|
#include "third_party/boringssl/src/pki/trust_store.h"
|
||||||
#include "third_party/boringssl/src/pki/trust_store_collection.h"
|
#include "third_party/boringssl/src/pki/trust_store_collection.h"
|
||||||
#include "third_party/boringssl/src/pki/trust_store_in_memory.h"
|
#include "third_party/boringssl/src/pki/trust_store_in_memory.h"
|
||||||
|
#include "url/url_canon.h"
|
||||||
|
|
||||||
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
|
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
|
||||||
#include "base/version_info/version_info.h" // nogncheck
|
#include "base/version_info/version_info.h" // nogncheck
|
||||||
@ -188,6 +192,37 @@ bool IsEVCandidate(const EVRootCAMetadata* ev_metadata,
|
|||||||
return !oids.empty();
|
return !oids.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsSelfSignedCertOnLocalNetwork(const X509Certificate* cert,
|
||||||
|
const std::string& hostname) {
|
||||||
|
if (!base::FeatureList::IsEnabled(
|
||||||
|
features::kSelfSignedLocalNetworkInterstitial)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
url::CanonHostInfo host_info;
|
||||||
|
std::string canonicalized_hostname =
|
||||||
|
CanonicalizeHostSupportsBareIPV6(hostname, &host_info);
|
||||||
|
if (canonicalized_hostname.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (host_info.IsIPAddress()) {
|
||||||
|
base::span<uint8_t> ip_span(host_info.address);
|
||||||
|
// AddressLength() is always 0, 4, or 16, so it's safe to cast to unsigned.
|
||||||
|
IPAddress ip(
|
||||||
|
ip_span.first(static_cast<unsigned>(host_info.AddressLength())));
|
||||||
|
if (ip.IsPubliclyRoutable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!base::EndsWith(canonicalized_hostname, ".local",
|
||||||
|
base::CompareCase::INSENSITIVE_ASCII) &&
|
||||||
|
!base::EndsWith(canonicalized_hostname, ".local.",
|
||||||
|
base::CompareCase::INSENSITIVE_ASCII)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return X509Certificate::IsSelfSigned(cert->cert_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
// CertVerifyProcTrustStore wraps a SystemTrustStore with additional trust
|
// CertVerifyProcTrustStore wraps a SystemTrustStore with additional trust
|
||||||
// anchors and TestRootCerts.
|
// anchors and TestRootCerts.
|
||||||
class CertVerifyProcTrustStore {
|
class CertVerifyProcTrustStore {
|
||||||
@ -1158,9 +1193,13 @@ int AssignVerifyResult(X509Certificate* input_cert,
|
|||||||
verify_result->policy_compliance = delegate_data->ct_policy_compliance;
|
verify_result->policy_compliance = delegate_data->ct_policy_compliance;
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsCertStatusError(verify_result->cert_status)
|
if (IsCertStatusError(verify_result->cert_status)) {
|
||||||
? MapCertStatusToNetError(verify_result->cert_status)
|
if (IsSelfSignedCertOnLocalNetwork(input_cert, hostname)) {
|
||||||
: OK;
|
verify_result->cert_status |= CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK;
|
||||||
|
}
|
||||||
|
return MapCertStatusToNetError(verify_result->cert_status);
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if retrying path building with a less stringent signature
|
// Returns true if retrying path building with a less stringent signature
|
||||||
|
@ -20,8 +20,10 @@
|
|||||||
#include "base/time/time.h"
|
#include "base/time/time.h"
|
||||||
#include "components/network_time/time_tracker/time_tracker.h"
|
#include "components/network_time/time_tracker/time_tracker.h"
|
||||||
#include "net/base/features.h"
|
#include "net/base/features.h"
|
||||||
|
#include "net/base/ip_address.h"
|
||||||
#include "net/base/net_errors.h"
|
#include "net/base/net_errors.h"
|
||||||
#include "net/base/test_completion_callback.h"
|
#include "net/base/test_completion_callback.h"
|
||||||
|
#include "net/cert/cert_status_flags.h"
|
||||||
#include "net/cert/cert_verify_proc.h"
|
#include "net/cert/cert_verify_proc.h"
|
||||||
#include "net/cert/crl_set.h"
|
#include "net/cert/crl_set.h"
|
||||||
#include "net/cert/do_nothing_ct_verifier.h"
|
#include "net/cert/do_nothing_ct_verifier.h"
|
||||||
@ -29,6 +31,7 @@
|
|||||||
#include "net/cert/internal/system_trust_store.h"
|
#include "net/cert/internal/system_trust_store.h"
|
||||||
#include "net/cert/sct_status_flags.h"
|
#include "net/cert/sct_status_flags.h"
|
||||||
#include "net/cert/time_conversions.h"
|
#include "net/cert/time_conversions.h"
|
||||||
|
#include "net/cert/x509_certificate.h"
|
||||||
#include "net/cert/x509_util.h"
|
#include "net/cert/x509_util.h"
|
||||||
#include "net/cert_net/cert_net_fetcher_url_request.h"
|
#include "net/cert_net/cert_net_fetcher_url_request.h"
|
||||||
#include "net/http/transport_security_state.h"
|
#include "net/http/transport_security_state.h"
|
||||||
@ -2111,4 +2114,211 @@ TEST_F(CertVerifyProcBuiltinTest, IterationLimit) {
|
|||||||
EXPECT_EQ(true, event->params.FindBool("exceeded_iteration_limit"));
|
EXPECT_EQ(true, event->params.FindBool("exceeded_iteration_limit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CertVerifyProcBuiltinSelfSignedTest
|
||||||
|
: public CertVerifyProcBuiltinTest,
|
||||||
|
public testing::WithParamInterface<bool> {
|
||||||
|
public:
|
||||||
|
CertVerifyProcBuiltinSelfSignedTest() {
|
||||||
|
if (GetParam()) {
|
||||||
|
feature_list_.InitAndEnableFeature(
|
||||||
|
features::kSelfSignedLocalNetworkInterstitial);
|
||||||
|
} else {
|
||||||
|
feature_list_.InitAndDisableFeature(
|
||||||
|
features::kSelfSignedLocalNetworkInterstitial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_refptr<X509Certificate> CreateSelfSigned(
|
||||||
|
std::string_view subject_dns_name) {
|
||||||
|
// Create a chain of size 1, which will result in a self-signed certificate
|
||||||
|
std::vector<std::unique_ptr<CertBuilder>> builders =
|
||||||
|
CertBuilder::CreateSimpleChain(1);
|
||||||
|
base::Time not_before = base::Time::Now() - base::Days(1);
|
||||||
|
base::Time not_after = base::Time::Now() + base::Days(1);
|
||||||
|
builders[0]->SetValidity(not_before, not_after);
|
||||||
|
builders[0]->SetSubjectAltName(subject_dns_name);
|
||||||
|
return builders[0]->GetX509Certificate();
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_refptr<X509Certificate> CreateSelfSignedIPSubject(
|
||||||
|
std::string_view ip_address) {
|
||||||
|
// Create a chain of size 1, which will result in a self-signed certificate
|
||||||
|
std::vector<std::unique_ptr<CertBuilder>> builders =
|
||||||
|
CertBuilder::CreateSimpleChain(1);
|
||||||
|
base::Time not_before = base::Time::Now() - base::Days(1);
|
||||||
|
base::Time not_after = base::Time::Now() + base::Days(1);
|
||||||
|
builders[0]->SetValidity(not_before, not_after);
|
||||||
|
IPAddress ip;
|
||||||
|
if (!ParseURLHostnameToAddress(ip_address, &ip)) {
|
||||||
|
ADD_FAILURE() << "Failed to parse IP address";
|
||||||
|
}
|
||||||
|
|
||||||
|
builders[0]->SetSubjectAltNames({}, {ip});
|
||||||
|
return builders[0]->GetX509Certificate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
base::test::ScopedFeatureList feature_list_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest,
|
||||||
|
SelfSignedCertOnLocalNetworkHostname) {
|
||||||
|
scoped_refptr<X509Certificate> cert = CreateSelfSigned("testurl.local");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "testurl.local", 0, &verify_result, &verify_net_log_source,
|
||||||
|
callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
if (GetParam()) {
|
||||||
|
EXPECT_TRUE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_SELF_SIGNED_LOCAL_NETWORK));
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest, SelfSignedCertOnLocalNetworkIP) {
|
||||||
|
scoped_refptr<X509Certificate> cert =
|
||||||
|
CreateSelfSignedIPSubject("192.168.0.1");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "192.168.0.1", 0, &verify_result, &verify_net_log_source,
|
||||||
|
callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
if (GetParam()) {
|
||||||
|
EXPECT_TRUE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_SELF_SIGNED_LOCAL_NETWORK));
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest, SelfSignedCertOnLocalNetworkIPv6) {
|
||||||
|
scoped_refptr<X509Certificate> cert =
|
||||||
|
CreateSelfSignedIPSubject("[fc00:0:0:0:0:0:0:0]");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "fc00:0:0:0:0:0:0:0", 0, &verify_result, &verify_net_log_source,
|
||||||
|
callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
if (GetParam()) {
|
||||||
|
EXPECT_TRUE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_SELF_SIGNED_LOCAL_NETWORK));
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest, NonSelfSignedCertOnLocalNetwork) {
|
||||||
|
std::vector<std::unique_ptr<CertBuilder>> builders =
|
||||||
|
CertBuilder::CreateSimpleChain(2);
|
||||||
|
|
||||||
|
base::Time not_before = base::Time::Now() - base::Days(2);
|
||||||
|
base::Time not_after = base::Time::Now() - base::Days(2);
|
||||||
|
builders[0]->SetValidity(not_before, not_after);
|
||||||
|
builders[0]->SetSubjectAltName("testurl.local");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(builders[0]->GetX509CertificateChain(), "testurl.local", 0,
|
||||||
|
&verify_result, &verify_net_log_source, callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest,
|
||||||
|
SelfSignedCertNotLocalNetworkHostname) {
|
||||||
|
scoped_refptr<X509Certificate> cert = CreateSelfSigned("www.example.com");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "www.example.com", 0, &verify_result, &verify_net_log_source,
|
||||||
|
callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest, SelfSignedCertNotLocalNetworkIP) {
|
||||||
|
scoped_refptr<X509Certificate> cert = CreateSelfSignedIPSubject("8.8.8.8");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "8.8.8.8", 0, &verify_result, &verify_net_log_source,
|
||||||
|
callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest, SelfSignedCertNotLocalNetworkIPv6) {
|
||||||
|
scoped_refptr<X509Certificate> cert =
|
||||||
|
CreateSelfSignedIPSubject("[2001:4860:4860::8888]");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "2001:4860:4860::8888", 0, &verify_result,
|
||||||
|
&verify_net_log_source, callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(CertVerifyProcBuiltinSelfSignedTest,
|
||||||
|
SelfSignedCertOnLocalNetworkHostnameNameMismatchTakesPrecedence) {
|
||||||
|
scoped_refptr<X509Certificate> cert = CreateSelfSigned("nottesturl.local");
|
||||||
|
|
||||||
|
CertVerifyResult verify_result;
|
||||||
|
NetLogSource verify_net_log_source;
|
||||||
|
TestCompletionCallback callback;
|
||||||
|
Verify(cert, "testurl.local", 0, &verify_result, &verify_net_log_source,
|
||||||
|
callback.callback());
|
||||||
|
int error = callback.WaitForResult();
|
||||||
|
|
||||||
|
if (GetParam()) {
|
||||||
|
EXPECT_TRUE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_COMMON_NAME_INVALID));
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(verify_result.cert_status &
|
||||||
|
CERT_STATUS_SELF_SIGNED_LOCAL_NETWORK);
|
||||||
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(SelfSignedInterstitial,
|
||||||
|
CertVerifyProcBuiltinSelfSignedTest,
|
||||||
|
testing::Bool());
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
|
@ -452,12 +452,9 @@ bool X509Certificate::VerifyHostname(
|
|||||||
// access, i.e. the thing displayed in the URL bar.
|
// access, i.e. the thing displayed in the URL bar.
|
||||||
// Presented identifier(s) == name(s) the server knows itself as, in its cert.
|
// Presented identifier(s) == name(s) the server knows itself as, in its cert.
|
||||||
|
|
||||||
// CanonicalizeHost requires surrounding brackets to parse an IPv6 address.
|
|
||||||
const std::string host_or_ip = hostname.find(':') != std::string::npos
|
|
||||||
? base::StrCat({"[", hostname, "]"})
|
|
||||||
: std::string(hostname);
|
|
||||||
url::CanonHostInfo host_info;
|
url::CanonHostInfo host_info;
|
||||||
std::string reference_name = CanonicalizeHost(host_or_ip, &host_info);
|
std::string reference_name =
|
||||||
|
CanonicalizeHostSupportsBareIPV6(hostname, &host_info);
|
||||||
|
|
||||||
// If the host cannot be canonicalized, fail fast.
|
// If the host cannot be canonicalized, fail fast.
|
||||||
if (reference_name.empty())
|
if (reference_name.empty())
|
||||||
|
Reference in New Issue
Block a user