diff options
-rw-r--r-- | chrome/browser/ui/cocoa/certificate_viewer.mm | 54 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 34 | ||||
-rw-r--r-- | net/base/x509_certificate_mac.cc | 168 |
3 files changed, 174 insertions, 82 deletions
diff --git a/chrome/browser/ui/cocoa/certificate_viewer.mm b/chrome/browser/ui/cocoa/certificate_viewer.mm index 8c5a954..3b6a656 100644 --- a/chrome/browser/ui/cocoa/certificate_viewer.mm +++ b/chrome/browser/ui/cocoa/certificate_viewer.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -34,12 +34,50 @@ void ShowCertificateViewer(gfx::NativeWindow parent, for (size_t i = 0; i < ca_certs.size(); ++i) CFArrayAppendValue(certificates, ca_certs[i]); - [[[SFCertificatePanel alloc] init] - beginSheetForWindow:parent - modalDelegate:nil - didEndSelector:NULL - contextInfo:NULL - certificates:reinterpret_cast<NSArray*>(certificates.get()) - showGroup:YES]; + // Explicitly disable revocation checking, regardless of user preferences + // or system settings. The behaviour of SFCertificatePanel is to call + // SecTrustEvaluate on the certificate(s) supplied, effectively + // duplicating the behaviour of net::X509Certificate::Verify(). However, + // this call stalls the UI if revocation checking is enabled in the + // Keychain preferences or if the cert may be an EV cert. By disabling + // revocation checking, the stall is limited to the time taken for path + // building and verification, which should be minimized due to the path + // being provided in |certificates|. This does not affect normal + // revocation checking from happening, which is controlled by + // net::X509Certificate::Verify() and user preferences, but will prevent + // the certificate viewer UI from displaying which certificate is revoked. + // This is acceptable, as certificate revocation will still be shown in + // the page info bubble if a certificate in the chain is actually revoked. + base::mac::ScopedCFTypeRef<CFMutableArrayRef> policies( + CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); + if (!policies.get()) { + NOTREACHED(); + return; + } + // Add a basic X.509 policy, in order to match the behaviour of + // SFCertificatePanel when no policies are specified. + SecPolicyRef basic_policy = NULL; + OSStatus status = net::X509Certificate::CreateBasicX509Policy(&basic_policy); + if (status != noErr) { + NOTREACHED(); + return; + } + CFArrayAppendValue(policies, basic_policy); + CFRelease(basic_policy); + + status = net::X509Certificate::CreateRevocationPolicies(false, policies); + if (status != noErr) { + NOTREACHED(); + return; + } + + SFCertificatePanel* panel = [[SFCertificatePanel alloc] init]; + [panel setPolicies:(id)policies.get()]; + [panel beginSheetForWindow:parent + modalDelegate:nil + didEndSelector:NULL + contextInfo:NULL + certificates:reinterpret_cast<NSArray*>(certificates.get()) + showGroup:YES]; // The SFCertificatePanel releases itself when the sheet is dismissed. } diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index f01f9f1..62b51c3 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -257,15 +257,41 @@ class NET_API X509Certificate // Do any of the given issuer names appear in this cert's chain of trust? bool IsIssuedBy(const std::vector<CertPrincipal>& valid_issuers); - // Creates a security policy for SSL client certificates. - static OSStatus CreateSSLClientPolicy(SecPolicyRef* outPolicy); + // Creates a security policy for certificates used as client certificates + // in SSL. + // If a policy is successfully created, it will be stored in + // |*policy| and ownership transferred to the caller. + static OSStatus CreateSSLClientPolicy(SecPolicyRef* policy); + + // Creates a security policy for certificates used by SSL servers. + // |hostname| is an optionally-supplied string indicating the name to verify + // the server certificate as; if it is empty, no hostname verification will + // happen. + // If a policy is successfully created, it will be stored in |*policy| and + // ownership transferred to the caller. + static OSStatus CreateSSLServerPolicy(const std::string& hostname, + SecPolicyRef* policy); + + // Creates a security policy for basic X.509 validation. If the policy is + // successfully created, it will be stored in |*policy| and ownership + // transferred to the caller. + static OSStatus CreateBasicX509Policy(SecPolicyRef* policy); + + // Creates security policies to control revocation checking (OCSP and CRL). + // If |enable_revocation_checking| is false, the policies returned will be + // explicitly disabled from accessing the network or the cache. This may be + // used to override system settings regarding revocation checking. + // If the policies are successfully created, they will be appended to + // |policies|. + static OSStatus CreateRevocationPolicies(bool enable_revocation_checking, + CFMutableArrayRef policies); // Adds all available SSL client identity certs to the given vector. // |server_domain| is a hint for which domain the cert is to be sent to // (a cert previously specified as the default for that domain will be given // precedence and returned first in the output vector.) - // If valid_issuers is non-empty, only certs that were transitively issued by - // one of the given names will be included in the list. + // If valid_issuers is non-empty, only certs that were transitively issued + // by one of the given names will be included in the list. static bool GetSSLClientCertificates( const std::string& server_domain, const std::vector<CertPrincipal>& valid_issuers, diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc index 6c41c50..8f4ba4e 100644 --- a/net/base/x509_certificate_mac.cc +++ b/net/base/x509_certificate_mac.cc @@ -319,73 +319,22 @@ OSStatus CreateTrustPolicies(const std::string& hostname, int flags, // Create an SSL SecPolicyRef, and configure it to perform hostname // validation. The hostname check does 99% of what we want, with the // exception of dotted IPv4 addreses, which we handle ourselves below. - CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { - CSSM_APPLE_TP_SSL_OPTS_VERSION, - hostname.size(), - hostname.data(), - 0 - }; SecPolicyRef ssl_policy; - OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options, - sizeof(tp_ssl_options), &ssl_policy); + OSStatus status = X509Certificate::CreateSSLServerPolicy(hostname, + &ssl_policy); if (status) return status; CFArrayAppendValue(local_policies, ssl_policy); CFRelease(ssl_policy); - // Manually add revocation policies. In order to actually disable revocation - // checking, the SecTrustRef must have at least one revocation policy - // associated with it. If none are present, the Apple TP will add policies - // according to the system preferences, which will enable revocation - // checking even if the caller explicitly disabled it. An OCSP policy is - // used, rather than a CRL policy, because the Apple TP will force an OCSP - // policy to be present and enabled if it believes the certificate may chain - // to an EV root. By explicitly disabling network and OCSP cache access, - // then even if the Apple TP enables OCSP checking, no revocation checking - // will actually succeed. - CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options; - memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options)); - tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; - - if (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) { - // The default for the OCSP policy is to fetch responses via the network, - // unlike the CRL policy default. The policy is further modified to - // prefer OCSP over CRLs, if both are specified on the certificate. This - // is because an OCSP response is both sufficient and typically - // significantly smaller than the CRL counterpart. - tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT; - } else { - // Effectively disable OCSP checking by making it impossible to get an - // OCSP response. Even if the Apple TP forces OCSP, no checking will - // be able to succeed. If this happens, the Apple TP will report an error - // that OCSP was unavailable, but this will be handled and suppressed in - // X509Certificate::Verify(). - tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET | - CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE; - } - - SecPolicyRef ocsp_policy; - status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options, - sizeof(tp_ocsp_options), &ocsp_policy); + // Explicitly add revocation policies, in order to override system + // revocation checking policies and instead respect the application-level + // revocation preference. + status = X509Certificate::CreateRevocationPolicies( + (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED), + local_policies); if (status) return status; - CFArrayAppendValue(local_policies, ocsp_policy); - CFRelease(ocsp_policy); - - if (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) { - CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options; - memset(&tp_crl_options, 0, sizeof(tp_crl_options)); - tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; - tp_crl_options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET; - - SecPolicyRef crl_policy; - status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options, - sizeof(tp_crl_options), &crl_policy); - if (status) - return status; - CFArrayAppendValue(local_policies, crl_policy); - CFRelease(crl_policy); - } policies->reset(local_policies.release()); return noErr; @@ -1211,19 +1160,98 @@ bool X509Certificate::IsIssuedBy( } // static -OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) { - CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { - CSSM_APPLE_TP_SSL_OPTS_VERSION, - 0, - NULL, - CSSM_APPLE_TP_SSL_CLIENT - }; - return CreatePolicy(&CSSMOID_APPLE_TP_SSL, - &tp_ssl_options, - sizeof(tp_ssl_options), - out_policy); +OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* policy) { + CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options; + memset(&tp_ssl_options, 0, sizeof(tp_ssl_options)); + tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; + tp_ssl_options.Flags |= CSSM_APPLE_TP_SSL_CLIENT; + + return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options, + sizeof(tp_ssl_options), policy); +} + +// static +OSStatus X509Certificate::CreateSSLServerPolicy(const std::string& hostname, + SecPolicyRef* policy) { + CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options; + memset(&tp_ssl_options, 0, sizeof(tp_ssl_options)); + tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; + if (!hostname.empty()) { + tp_ssl_options.ServerName = hostname.data(); + tp_ssl_options.ServerNameLen = hostname.size(); + } + + return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options, + sizeof(tp_ssl_options), policy); +} + +// static +OSStatus X509Certificate::CreateBasicX509Policy(SecPolicyRef* policy) { + return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy); +} + +// static +OSStatus X509Certificate::CreateRevocationPolicies( + bool enable_revocation_checking, + CFMutableArrayRef policies) { + // In order to actually disable revocation checking, the SecTrustRef must + // have at least one revocation policy associated with it. If none are + // present, the Apple TP will add policies according to the system + // preferences, which will enable revocation checking even if the caller + // explicitly disabled it. An OCSP policy is used, rather than a CRL policy, + // because the Apple TP will force an OCSP policy to be present and enabled + // if it believes the certificate may chain to an EV root. By explicitly + // disabling network and OCSP cache access, then even if the Apple TP + // enables OCSP checking, no revocation checking will actually succeed. + CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options; + memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options)); + tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; + + if (enable_revocation_checking) { + // The default for the OCSP policy is to fetch responses via the network, + // unlike the CRL policy default. The policy is further modified to + // prefer OCSP over CRLs, if both are specified on the certificate. This + // is because an OCSP response is both sufficient and typically + // significantly smaller than the CRL counterpart. + tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT; + } else { + // Effectively disable OCSP checking by making it impossible to get an + // OCSP response. Even if the Apple TP forces OCSP, no checking will + // be able to succeed. If this happens, the Apple TP will report an error + // that OCSP was unavailable, but this will be handled and suppressed in + // X509Certificate::Verify(). + tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET | + CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE; + } + + SecPolicyRef ocsp_policy; + OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, + &tp_ocsp_options, sizeof(tp_ocsp_options), + &ocsp_policy); + if (status) + return status; + CFArrayAppendValue(policies, ocsp_policy); + CFRelease(ocsp_policy); + + if (enable_revocation_checking) { + CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options; + memset(&tp_crl_options, 0, sizeof(tp_crl_options)); + tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; + tp_crl_options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET; + + SecPolicyRef crl_policy; + status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options, + sizeof(tp_crl_options), &crl_policy); + if (status) + return status; + CFArrayAppendValue(policies, crl_policy); + CFRelease(crl_policy); + } + + return status; } + // static bool X509Certificate::GetSSLClientCertificates( const std::string& server_domain, |